Refactored process list collector

This commit is contained in:
Shay Nehmad 2020-01-20 17:12:12 +02:00
parent 04b7370575
commit 2286571a72
7 changed files with 98 additions and 68 deletions

View File

@ -1,3 +1,4 @@
AWS_COLLECTOR = "AwsCollector"
HOSTNAME_COLLECTOR = "HostnameCollector"
ENVIRONMENT_COLLECTOR = "EnvironmentCollector"
PROCESS_LIST_COLLECTOR = "ProcessListCollector"

View File

@ -62,44 +62,12 @@ class InfoCollector(object):
def get_info(self):
# Collect all hardcoded
self.get_process_list()
self.get_network_info()
self.get_azure_info()
# Collect all plugins
SystemInfoCollectorsHandler().execute_all_configured()
def get_process_list(self):
"""
Adds process information from the host to the system information.
Currently lists process name, ID, parent ID, command line
and the full image path of each process.
:return: None. Updates class information
"""
LOG.debug("Reading process list")
processes = {}
for process in psutil.process_iter():
try:
processes[process.pid] = {"name": process.name(),
"pid": process.pid,
"ppid": process.ppid(),
"cmdline": " ".join(process.cmdline()),
"full_image_path": process.exe(),
}
except (psutil.AccessDenied, WindowsError):
# we may be running as non root
# and some processes are impossible to acquire in Windows/Linux
# in this case we'll just add what we can
processes[process.pid] = {"name": "null",
"pid": process.pid,
"ppid": process.ppid(),
"cmdline": "ACCESS DENIED",
"full_image_path": "null",
}
continue
self.info['process_list'] = processes
def get_network_info(self):
"""
Adds network information from the host to the system information.

View File

@ -0,0 +1,50 @@
import logging
import psutil
from common.data.system_info_collectors_names import PROCESS_LIST_COLLECTOR
from infection_monkey.system_info.system_info_collector import SystemInfoCollector
logger = logging.getLogger(__name__)
# Linux doesn't have WindowsError
try:
WindowsError
except NameError:
# noinspection PyShadowingBuiltins
WindowsError = psutil.AccessDenied
class ProcessListCollector(SystemInfoCollector):
def __init__(self):
super(ProcessListCollector, self).__init__(name=PROCESS_LIST_COLLECTOR)
def collect(self) -> dict:
"""
Adds process information from the host to the system information.
Currently lists process name, ID, parent ID, command line
and the full image path of each process.
"""
logger.debug("Reading process list")
processes = {}
for process in psutil.process_iter():
try:
processes[process.pid] = {
"name": process.name(),
"pid": process.pid,
"ppid": process.ppid(),
"cmdline": " ".join(process.cmdline()),
"full_image_path": process.exe(),
}
except (psutil.AccessDenied, WindowsError):
# we may be running as non root and some processes are impossible to acquire in Windows/Linux.
# In this case we'll just add what we know.
processes[process.pid] = {
"name": "null",
"pid": process.pid,
"ppid": process.ppid(),
"cmdline": "ACCESS DENIED",
"full_image_path": "null",
}
continue
return {'process_list': processes}

View File

@ -1,3 +1,5 @@
from common.data.system_info_collectors_names import *
WARNING_SIGN = " \u26A0"
SCHEMA = {
@ -106,7 +108,7 @@ SCHEMA = {
{
"type": "string",
"enum": [
"EnvironmentCollector"
ENVIRONMENT_COLLECTOR
],
"title": "Collect which environment this machine is on (on prem/cloud)",
"attack_techniques": []
@ -114,7 +116,7 @@ SCHEMA = {
{
"type": "string",
"enum": [
"AwsCollector"
AWS_COLLECTOR
],
"title": "If on AWS, collect more information about the instance",
"attack_techniques": []
@ -122,11 +124,19 @@ SCHEMA = {
{
"type": "string",
"enum": [
"HostnameCollector"
HOSTNAME_COLLECTOR
],
"title": "Collect the machine's hostname",
"attack_techniques": []
},
{
"type": "string",
"enum": [
PROCESS_LIST_COLLECTOR
],
"title": "Collect running processes on the machine",
"attack_techniques": []
},
],
},
"post_breach_acts": {
@ -471,9 +481,10 @@ SCHEMA = {
"$ref": "#/definitions/system_info_collectors_classes"
},
"default": [
"EnvironmentCollector",
"AwsCollector",
"HostnameCollector"
ENVIRONMENT_COLLECTOR,
AWS_COLLECTOR,
HOSTNAME_COLLECTOR,
PROCESS_LIST_COLLECTOR
],
"description": "Determines which system information collectors will collect information."
},

View File

@ -6,7 +6,6 @@ from monkey_island.cc.services.config import ConfigService
from monkey_island.cc.services.node import NodeService
from monkey_island.cc.services.telemetry.processing.system_info_collectors.system_info_telemetry_dispatcher import \
SystemInfoTelemetryDispatcher
from monkey_island.cc.services.telemetry.zero_trust_tests.antivirus_existence import test_antivirus_existence
from monkey_island.cc.services.wmi_handler import WMIHandler
logger = logging.getLogger(__name__)
@ -18,8 +17,7 @@ def process_system_info_telemetry(telemetry_json):
process_ssh_info,
process_credential_info,
process_mimikatz_and_wmi_info,
test_antivirus_existence,
dispatcher.dispatch_to_relevant_collectors
dispatcher.dispatch_collector_results_to_relevant_processors
]
# Calling safe_process_telemetry so if one of the stages fail, we log and move on instead of failing the rest of

View File

@ -5,6 +5,7 @@ from common.data.system_info_collectors_names import *
from monkey_island.cc.services.telemetry.processing.system_info_collectors.aws import process_aws_telemetry
from monkey_island.cc.services.telemetry.processing.system_info_collectors.environment import process_environment_telemetry
from monkey_island.cc.services.telemetry.processing.system_info_collectors.hostname import process_hostname_telemetry
from monkey_island.cc.services.telemetry.zero_trust_tests.antivirus_existence import test_antivirus_existence
logger = logging.getLogger(__name__)
@ -12,6 +13,7 @@ SYSTEM_INFO_COLLECTOR_TO_TELEMETRY_PROCESSORS = {
AWS_COLLECTOR: [process_aws_telemetry],
ENVIRONMENT_COLLECTOR: [process_environment_telemetry],
HOSTNAME_COLLECTOR: [process_hostname_telemetry],
PROCESS_LIST_COLLECTOR: [test_antivirus_existence]
}
@ -32,9 +34,9 @@ class SystemInfoTelemetryDispatcher(object):
:param telemetry_json: Telemetry sent from the Monkey
"""
if "collectors" in telemetry_json["data"]:
self.dispatch_each_result_to_relevant_processors(telemetry_json)
self.dispatch_single_result_to_relevant_processor(telemetry_json)
def dispatch_each_result_to_relevant_processors(self, telemetry_json):
def dispatch_single_result_to_relevant_processor(self, telemetry_json):
relevant_monkey_guid = telemetry_json['monkey_guid']
for collector_name, collector_results in telemetry_json["data"]["collectors"].items():

View File

@ -7,16 +7,16 @@ from monkey_island.cc.models.zero_trust.event import Event
from monkey_island.cc.services.telemetry.zero_trust_tests.known_anti_viruses import ANTI_VIRUS_KNOWN_PROCESS_NAMES
def test_antivirus_existence(telemetry_json):
current_monkey = Monkey.get_single_monkey_by_guid(telemetry_json['monkey_guid'])
if 'process_list' in telemetry_json['data']:
def test_antivirus_existence(process_list_json, monkey_guid):
current_monkey = Monkey.get_single_monkey_by_guid(monkey_guid)
process_list_event = Event.create_event(
title="Process list",
message="Monkey on {} scanned the process list".format(current_monkey.hostname),
event_type=zero_trust_consts.EVENT_TYPE_MONKEY_LOCAL)
events = [process_list_event]
av_processes = filter_av_processes(telemetry_json)
av_processes = filter_av_processes(process_list_json["process_list"])
for process in av_processes:
events.append(Event.create_event(
@ -35,8 +35,8 @@ def test_antivirus_existence(telemetry_json):
)
def filter_av_processes(telemetry_json):
all_processes = list(telemetry_json['data']['process_list'].items())
def filter_av_processes(process_list):
all_processes = list(process_list.items())
av_processes = []
for process in all_processes:
process_name = process[1]['name']