diff --git a/monkey/monkey_island/cc/ui/src/components/Main.js b/monkey/monkey_island/cc/ui/src/components/Main.js
index 47116c5da..37eb97f3f 100644
--- a/monkey/monkey_island/cc/ui/src/components/Main.js
+++ b/monkey/monkey_island/cc/ui/src/components/Main.js
@@ -5,6 +5,7 @@ import {Container} from 'react-bootstrap';
import RunServerPage from 'components/pages/RunServerPage';
import ConfigurePage from 'components/pages/ConfigurePage';
import RunMonkeyPage from 'components/pages/RunMonkeyPage/RunMonkeyPage';
+import RunMonkeyPage2 from 'components/pages/RunMonkeyPage/RunMonkeyPage2';
import MapPage from 'components/pages/MapPage';
import TelemetryPage from 'components/pages/TelemetryPage';
import StartOverPage from 'components/pages/StartOverPage';
@@ -29,7 +30,7 @@ const reportZeroTrustRoute = '/report/zeroTrust';
class AppComponent extends AuthComponent {
updateStatus = () => {
- if (this.state.isLoggedIn === false){
+ if (this.state.isLoggedIn === false) {
return
}
this.auth.loggedIn()
@@ -148,6 +149,10 @@ class AppComponent extends AuthComponent {
{props.commands[0].command}
+ {cmdText}
-
- Go ahead and run the monkey! - (Or configure the monkey to fine tune its behavior) -
+ <>
-
-
- Choose the operating system where you want to run the monkey: -
-+ Go ahead and monitor the ongoing infection in the Infection Map view. +
+ > + ) + } - {this.state.ips.length > 1 ? -- Choose the interface to communicate with: -
- -- Copy the following command to your machine and run it with Administrator or root privileges. -
- {this.generateCmdDiv()} -+ Go ahead and run the monkey! + (Or configure the monkey to fine tune its behavior) +
+ {this.state.showManual ? +- Go ahead and monitor the ongoing infection in the Infection Map view. -
); } diff --git a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunMonkeyPage2.js b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunMonkeyPage2.js new file mode 100644 index 000000000..8edd0e44e --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunMonkeyPage2.js @@ -0,0 +1,472 @@ +import React from 'react'; +import {css} from '@emotion/core'; +import {Button, Col, Card, Nav, Collapse, Row} from 'react-bootstrap'; +import CopyToClipboard from 'react-copy-to-clipboard'; +import GridLoader from 'react-spinners/GridLoader'; + +import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; +import {faClipboard} from '@fortawesome/free-solid-svg-icons/faClipboard'; +import {faCheck} from '@fortawesome/free-solid-svg-icons/faCheck'; +import {faSync} from '@fortawesome/free-solid-svg-icons/faSync'; +import {faInfoCircle} from '@fortawesome/free-solid-svg-icons/faInfoCircle'; +import {faExclamationTriangle} from '@fortawesome/free-solid-svg-icons/faExclamationTriangle'; + +import {Link} from 'react-router-dom'; +import AuthComponent from '../../AuthComponent'; +import AwsRunTable from '../../run-monkey/AwsRunTable'; + +import MissingBinariesModal from '../../ui-components/MissingBinariesModal'; +import ManualRunOptions from './ManualRunOptions'; +import Emoji from '../../ui-components/Emoji'; + +const loading_css_override = css` + display: block; + margin-right: auto; + margin-left: auto; +`; + +class RunMonkeyPageComponent2 extends AuthComponent { + + constructor(props) { + super(props); + this.state = { + ips: [], + runningOnIslandState: 'not_running', + runningOnClientState: 'not_running', + awsClicked: false, + selectedIp: '0.0.0.0', + selectedOs: 'windows-32', + showManual: false, + showAws: false, + isOnAws: false, + awsUpdateClicked: false, + awsUpdateFailed: false, + awsMachines: [], + isLoadingAws: true, + isErrorWhileCollectingAwsMachines: false, + awsMachineCollectionErrorMsg: '', + showModal: false, + errorDetails: '' + }; + + this.closeModal = this.closeModal.bind(this); + } + + componentDidMount() { + this.authFetch('/api') + .then(res => res.json()) + .then(res => this.setState({ + ips: res['ip_addresses'], + selectedIp: res['ip_addresses'][0] + })); + + this.authFetch('/api/local-monkey') + .then(res => res.json()) + .then(res => { + if (res['is_running']) { + this.setState({runningOnIslandState: 'running'}); + } else { + this.setState({runningOnIslandState: 'not_running'}); + } + }); + + this.fetchAwsInfo(); + this.fetchConfig(); + + this.authFetch('/api/client-monkey') + .then(res => res.json()) + .then(res => { + if (res['is_running']) { + this.setState({runningOnClientState: 'running'}); + } else { + this.setState({runningOnClientState: 'not_running'}); + } + }); + + this.props.onStatusChange(); + } + + fetchAwsInfo() { + return this.authFetch('/api/remote-monkey?action=list_aws') + .then(res => res.json()) + .then(res => { + let is_aws = res['is_aws']; + if (is_aws) { + // On AWS! + // Checks if there was an error while collecting the aws machines. + let is_error_while_collecting_aws_machines = (res['error'] != null); + if (is_error_while_collecting_aws_machines) { + // There was an error. Finish loading, and display error message. + this.setState({ + isOnAws: true, + isErrorWhileCollectingAwsMachines: true, + awsMachineCollectionErrorMsg: res['error'], + isLoadingAws: false + }); + } else { + // No error! Finish loading and display machines for user + this.setState({isOnAws: true, awsMachines: res['instances'], isLoadingAws: false}); + } + } else { + // Not on AWS. Finish loading and don't display the AWS div. + this.setState({isOnAws: false, isLoadingAws: false}); + } + }); + } + + static generateLinuxCmd(ip, is32Bit) { + let bitText = is32Bit ? '32' : '64'; + return `wget --no-check-certificate https://${ip}:5000/api/monkey/download/monkey-linux-${bitText}; chmod +x monkey-linux-${bitText}; ./monkey-linux-${bitText} m0nk3y -s ${ip}:5000` + } + + static generateWindowsCmd(ip, is32Bit) { + let bitText = is32Bit ? '32' : '64'; + return `powershell [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}; (New-Object System.Net.WebClient).DownloadFile('https://${ip}:5000/api/monkey/download/monkey-windows-${bitText}.exe','.\\monkey.exe'); ;Start-Process -FilePath '.\\monkey.exe' -ArgumentList 'm0nk3y -s ${ip}:5000';`; + } + + runLocalMonkey = () => { + this.authFetch('/api/local-monkey', + { + method: 'POST', + headers: {'Content-Type': 'application/json'}, + body: JSON.stringify({action: 'run'}) + }) + .then(res => res.json()) + .then(res => { + if (res['is_running']) { + this.setState({ + runningOnIslandState: 'installing' + }); + } else { + /* If Monkey binaries are missing, change the state accordingly */ + if (res['error_text'].startsWith('Copy file failed')) { + this.setState({ + showModal: true, + errorDetails: res['error_text'] + } + ); + } + this.setState({ + runningOnIslandState: 'not_running' + }); + } + + this.props.onStatusChange(); + }); + }; + + generateCmdDiv() { + let isLinux = (this.state.selectedOs.split('-')[0] === 'linux'); + let is32Bit = (this.state.selectedOs.split('-')[1] === '32'); + let cmdText = ''; + if (isLinux) { + cmdText = RunMonkeyPageComponent2.generateLinuxCmd(this.state.selectedIp, is32Bit); + } else { + cmdText = RunMonkeyPageComponent2.generateWindowsCmd(this.state.selectedIp, is32Bit); + } + return ( +{cmdText}
+
+
+ Go ahead and run the monkey! + (Or configure the monkey to fine tune its behavior) +
+
+
+
+ OR +
++ +
++ Choose the operating system where you want to run the monkey: +
++ Choose the interface to communicate with: +
+ ++ Copy the following command to your machine and run it with Administrator or root privileges. +
+ {this.generateCmdDiv()} ++ OR +
+ : + null + } + { + this.state.isOnAws ? ++ +
+ : + null + } +
+ {this.state.awsMachineCollectionErrorMsg}
+ Are you sure you've set the correct role on your Island AWS machine?
+ Not sure what this is? Read
+ the documentation!
+
+ Go ahead and monitor the ongoing infection in the Infection Map view. +
+ + ); + } +} + +export default RunMonkeyPageComponent2; diff --git a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/CommandTypes.js b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunOptions.js similarity index 100% rename from monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/CommandTypes.js rename to monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunOptions.js diff --git a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/commands/local_linux_curl.js b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/commands/local_linux_curl.js new file mode 100644 index 000000000..fb0171bfd --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/commands/local_linux_curl.js @@ -0,0 +1,13 @@ +import {OS_TYPES} from '../OsTypes'; + + +export default function generateLocalLinuxCurl(ip, osType) { + let bitText = osType === OS_TYPES.LINUX_32 ? '32' : '64'; + return `curl https://${ip}:5000/api/monkey/download/monkey-linux-${bitText} -k + -o monkey-linux-${bitText}; + chmod +x monkey-linux-${bitText}; + ./monkey-linux-${bitText} m0nk3y -s ${ip}:5000\`;`; + } + + + diff --git a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/commands/local_linux_wget.js b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/commands/local_linux_wget.js new file mode 100644 index 000000000..766822ee1 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/commands/local_linux_wget.js @@ -0,0 +1,10 @@ +import {OS_TYPES} from '../OsTypes'; + + +export default function generateLocalLinuxWget(ip, osType) { + let bitText = osType === OS_TYPES.LINUX_32 ? '32' : '64'; + return `wget --no-check-certificate https://${ip}:5000/api/monkey/download/ + monkey-linux-${bitText}; + chmod +x monkey-linux-${bitText}; + ./monkey-linux-${bitText} m0nk3y -s ${ip}:5000`; + } diff --git a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/commands/local_windows_cmd.js b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/commands/local_windows_cmd.js new file mode 100644 index 000000000..74afbe512 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/commands/local_windows_cmd.js @@ -0,0 +1,10 @@ +import {OS_TYPES} from '../OsTypes'; + + +export default function generateLocalWindowsCmd(ip, osType) { + let bitText = osType === OS_TYPES.WINDOWS_32 ? '32' : '64'; + return `powershell [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}; + (New-Object System.Net.WebClient).DownloadFile('https://${ip}:5000/api/monkey/download/ + monkey-windows-${bitText}.exe','.\\monkey.exe'); + ;Start-Process -FilePath '.\\monkey.exe' -ArgumentList 'm0nk3y -s ${ip}:5000';`; +} diff --git a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/commands/local_windows_powershell.js b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/commands/local_windows_powershell.js new file mode 100644 index 000000000..1ebd1f4ac --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/commands/local_windows_powershell.js @@ -0,0 +1,10 @@ +import {OS_TYPES} from '../OsTypes'; + + +export default function generateLocalWindowsPowershell(ip, osType) { + let bitText = osType === OS_TYPES.WINDOWS_32 ? '32' : '64'; + return `[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}; + (New-Object System.Net.WebClient).DownloadFile('https://${ip}:5000/api/monkey/download/ + monkey-windows-${bitText}.exe','.\\monkey.exe'); + ;Start-Process -FilePath '.\\monkey.exe' -ArgumentList 'm0nk3y -s ${ip}:5000';`; +} diff --git a/monkey/monkey_island/cc/ui/src/components/ui-components/DropdownSelect.js b/monkey/monkey_island/cc/ui/src/components/ui-components/DropdownSelect.js new file mode 100644 index 000000000..d57f14fe4 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/ui-components/DropdownSelect.js @@ -0,0 +1,62 @@ +import React, {useState} from 'react'; +import {Dropdown} from 'react-bootstrap'; +import PropTypes from 'prop-types'; + +export default function DropdownSelect(props) { + const [selectedOption, setSelectedOption] = useState(props.defaultKey); + + function generateDropdownItems(data) { + if (Array.isArray(data)) { + return generateDropdownItemsFromArray(data); + } else if (typeof data === 'object') { + return generateDropdownItemsFromObject(data); + } else { + throw "Component can only generate dropdown intems from lists and objects." + } + } + + function generateDropdownItemsFromArray(data) { + const dropdownItems = []; + for (let i = 0; i < data.length; i++) { + dropdownItems.push(generateDropdownItem(i, data[i])); + } + return dropdownItems; + } + + function generateDropdownItemsFromObject(data) { + const dropdownItems = []; + for (let [key, value] of Object.entries(data)) { + dropdownItems.push(generateDropdownItem(key, value)); + } + return dropdownItems; + } + + function generateDropdownItem(key, value) { + return ( +