diff --git a/monkey/infection_monkey/Pipfile b/monkey/infection_monkey/Pipfile index 5c63ff709..da00a1fcb 100644 --- a/monkey/infection_monkey/Pipfile +++ b/monkey/infection_monkey/Pipfile @@ -31,6 +31,12 @@ ScoutSuite = {git = "git://github.com/guardicode/ScoutSuite"} pyopenssl = "==19.0.0" # We can't build 32bit ubuntu12 binary with newer versions of pyopenssl pypsrp = "*" typing-extensions = "*" +cython = "*" # Remove this after removing pyspnego +# Pinning pyspnego to this commit resolves #1456. A new pyspnego release that includes this commit +# is expected after 2021-10-01. Once a new version of pyspnego is released (v0.2.0?), both pyspnego +# and cython can be removed from this Pipfile (since pyspnego is a dependency of pypsrp and pypsrp +# has no hard version requirement. +pyspnego = {editable = true, ref = "3f748f210e4fb6b186b0036e1a0bf38762d64c37", git = "https://github.com/jborean93/pyspnego"} [dev-packages] diff --git a/monkey/infection_monkey/Pipfile.lock b/monkey/infection_monkey/Pipfile.lock index 53ff20a64..51510f2e0 100644 --- a/monkey/infection_monkey/Pipfile.lock +++ b/monkey/infection_monkey/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "96a125018d143a7446fe9b2849991c00d79f37c433694db77e616c1135baeaf9" + "sha256": "e4052afd20556222b3cf8266aeca93f39568da6d1219b108b79070fa198ad908" }, "pipfile-spec": 6, "requires": { @@ -26,11 +26,11 @@ }, "altgraph": { "hashes": [ - "sha256:1f05a47122542f97028caf78775a095fbe6a2699b5089de8477eb583167d69aa", - "sha256:c623e5f3408ca61d4016f23a681b9adb100802ca3e3da5e718915a9e4052cebe" + "sha256:743628f2ac6a7c26f5d9223c91ed8ecbba535f506f4b6f558885a8a56a105857", + "sha256:ebf2269361b47d97b3b88e696439f6e4cbc607c17c51feb1754f90fb79839158" ], "index": "pypi", - "version": "==0.17" + "version": "==0.17.2" }, "asn1crypto": { "hashes": [ @@ -69,19 +69,19 @@ }, "boto3": { "hashes": [ - "sha256:461f659c06f9f56693cebbca70b11866f096021eafbd949a3c029c3a8adee6a4", - "sha256:596d2afda27ae3d9a10112a475aa25c4d6b5cf023919e370ad8e6c6ae04d57a6" + "sha256:3a270f002818703d5f2eef5296c2fd8b44ef21a3f3290a716ec2202da8dd464e", + "sha256:8bc3211a7d7767c2c72ae9b226edb5eec5bb96989c83696832b8a5c35feb356a" ], "markers": "python_version >= '3.6'", - "version": "==1.18.33" + "version": "==1.18.44" }, "botocore": { "hashes": [ - "sha256:204327b9a33e3ae5207ff9acdd7d3b6d1f99f5dc9165a4d843d6f1a566f3006c", - "sha256:b321b570a0da4c6280e737d817c8f740bce0ef914f564e1c27246c7ae76b4c31" + "sha256:2e134c9f799015e448086ed2b809fe50cc776f6600f093d1a44772288e61260f", + "sha256:c7640cb49c0e009bea4ad767715acbe0d305b7007235f52422bf31b5d23be8f1" ], "markers": "python_version >= '3.6'", - "version": "==1.21.33" + "version": "==1.21.44" }, "certifi": { "hashes": [ @@ -151,11 +151,11 @@ }, "charset-normalizer": { "hashes": [ - "sha256:0c8911edd15d19223366a194a513099a302055a962bca2cec0f54b8b63175d8b", - "sha256:f23667ebe1084be45f6ae0538e4a5a865206544097e4e8bbcacf42cd02a348f3" + "sha256:5d209c0a931f215cee683b6445e2d77677e7e75e159f78def0db09d68fafcaa6", + "sha256:5ec46d183433dcbd0ab716f2d7f29d8dee50505b3fdb40c6b985c7c4f5a3591f" ], "markers": "python_version >= '3'", - "version": "==2.0.4" + "version": "==2.0.6" }, "cheroot": { "hashes": [ @@ -229,6 +229,51 @@ "index": "pypi", "version": "==2.5" }, + "cython": { + "hashes": [ + "sha256:09ac3087ac7a3d489ebcb3fb8402e00c13d1a3a1c6bc73fd3b0d756a3e341e79", + "sha256:0a142c6b862e6ed6b02209d543062c038c110585b5e32d1ad7c9717af4f07e41", + "sha256:0d414458cb22f8a90d64260da6dace5d5fcebde43f31be52ca51f818c46db8cb", + "sha256:10cb3def9774fa99e4583617a5616874aed3255dc241fd1f4a3c2978c78e1c53", + "sha256:112efa54a58293a4fb0acf0dd8e5b3736e95b595eee24dd88615648e445abe41", + "sha256:166f9f29cd0058ce1a14a7b3a2458b849ed34b1ec5fd4108af3fdd2c24afcbb0", + "sha256:2d9e61ed1056a3b6a4b9156b62297ad18b357a7948e57a2f49b061217696567e", + "sha256:2f41ef7edd76dd23315925e003f0c58c8585f3ab24be6885c4b3f60e77c82746", + "sha256:37bcfa5df2a3009f49624695d917c3804fccbdfcdc5eda6378754a879711a4d5", + "sha256:416046a98255eff97ec02077d20ebeaae52682dfca1c35aadf31260442b92514", + "sha256:4cf4452f0e4d50e11701bca38f3857fe6fa16593e7fd6a4d5f7be66f611b7da2", + "sha256:55b0ee28c2c8118bfb3ad9b25cf7a6cbd724e442ea96956e32ccd908d5e3e043", + "sha256:5dd56d0be50073f0e54825a8bc3393852de0eed126339ecbca0ae149dba55cfc", + "sha256:5fa12ebafc2f688ea6d26ab6d1d2e634a9872509ba7135b902bb0d8b368fb04b", + "sha256:5fb977945a2111f6b64501fdf7ed0ec162cc502b84457fd648d6a558ea8de0d6", + "sha256:60c958bcab0ff315b4036a949bed1c65334e1f6a69e17e9966d742febb59043a", + "sha256:661dbdea519d9cfb288867252b75fef73ffa8e8bb674cec27acf70646afb369b", + "sha256:6a2cf2ccccc25413864928dfd730c29db6f63eaf98206c1e600003a445ca7f58", + "sha256:6ade74eece909fd3a437d9a5084829180751d7ade118e281e9824dd75eafaff2", + "sha256:73ac33a4379056a02031baa4def255717fadb9181b5ac2b244792d53eae1c925", + "sha256:76cbca0188d278e93d12ebdaf5990678e6e436485fdfad49dbe9b07717d41a3c", + "sha256:774cb8fd931ee1ba52c472bc1c19077cd6895c1b24014ae07bb27df59aed5ebe", + "sha256:821c2d416ad7d006b069657ee1034c0e0cb45bdbe9ab6ab631e8c495dfcfa4ac", + "sha256:84826ec1c11cda56261a252ddecac0c7d6b02e47e81b94f40b27b4c23c29c17c", + "sha256:854fe2193d3ad4c8b61932ff54d6dbe10c5fa8749eb8958d72cc0ab28243f833", + "sha256:88dc3c250dec280b0489a83950b15809762e27232f4799b1b8d0bad503f5ab84", + "sha256:8cb87777e82d1996aef6c146560a19270684271c9c669ba62ac6803b3cd2ff82", + "sha256:91339ee4b465924a3ea4b2a9cec7f7227bc4cadf673ce859d24c2b9ef60b1214", + "sha256:9164aeef1af6f837e4fc20402a31d256188ba4d535e262c6cb78caf57ad744f8", + "sha256:a102cfa795c6b3b81a29bdb9dbec545367cd7f353c03e6f30a056fdfefd92854", + "sha256:ad43e684ade673565f6f9d6638015112f6c7f11aa2a632167b79014f613f0f5f", + "sha256:afb521523cb46ddaa8d269b421f88ea2731fee05e65b952b96d4db760f5a2a1c", + "sha256:b28f92e617f540d3f21f8fd479a9c6491be920ffff672a4c61b7fc4d7f749f39", + "sha256:bc05de569f811be1fcfde6756c9048ae518f0c4b6d9f8f024752c5365d934cac", + "sha256:cdf04d07c3600860e8c2ebaad4e8f52ac3feb212453c1764a49ac08c827e8443", + "sha256:d8d1a087f35e39384303f5e6b75d465d6f29d746d7138eae9d3b6e8e6f769eae", + "sha256:eb2843f8cc01c645725e6fc690a84e99cdb266ce8ebe427cf3a680ff09f876aa", + "sha256:f2e9381497b12e8f622af620bde0d1d094035d79b899abb2ddd3a7891f535083", + "sha256:f96411f0120b5cae483923aaacd2872af8709be4b46522daedc32f051d778385" + ], + "index": "pypi", + "version": "==0.29.24" + }, "dnspython": { "hashes": [ "sha256:95d12f6ef0317118d2a1a6fc49aac65ffec7eb8087474158f42f26a639135216", @@ -268,11 +313,11 @@ }, "humanfriendly": { "hashes": [ - "sha256:332da98c24cc150efcc91b5508b19115209272bfdf4b0764a56795932f854271", - "sha256:f7dba53ac7935fd0b4a2fc9a29e316ddd9ea135fb3052d3d0279d10c18ff9c48" + "sha256:1697e1a8a8f550fd43c2865cd84542fc175a61dcb779b6fee18cf6b6ccba1477", + "sha256:6b0b831ce8f15f7300721aa49829fc4e83921a9a301cc7f606be6686a2288ddc" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==9.2" + "version": "==10.0" }, "idna": { "hashes": [ @@ -441,11 +486,11 @@ }, "minidump": { "hashes": [ - "sha256:67b3327cb96e319633653a353c6281703772335dc84797d6fdce7daf0b3be077", - "sha256:fdd9eb4566b6d3dabc205bf644ded724067bdbdb453eb418565261e5520b3537" + "sha256:5b9872a6417be626b7bc8db2f9feb6f9089e48ecfce372829a3418575fe22a1c", + "sha256:f545257f16437959d4c460dbb39b245ac019ba5f10a3bdd9b2efec4fad0d29e7" ], "markers": "python_version >= '3.6'", - "version": "==0.0.19" + "version": "==0.0.20" }, "minikerberos": { "hashes": [ @@ -457,11 +502,11 @@ }, "more-itertools": { "hashes": [ - "sha256:2cf89ec599962f2ddc4d568a05defc40e0a587fbc10d5989713638864c36be4d", - "sha256:83f0308e05477c68f56ea3a888172c78ed5d5b3c282addb67508e7ba6c8f813a" + "sha256:1debcabeb1df793814859d64a81ad7cb10504c24349368ccf214c664c474f41f", + "sha256:56ddac45541718ba332db05f464bebfb0768110111affd27f66e0051f276fa43" ], "markers": "python_version >= '3.5'", - "version": "==8.8.0" + "version": "==8.10.0" }, "msldap": { "hashes": [ @@ -538,10 +583,10 @@ }, "policyuniverse": { "hashes": [ - "sha256:1d5136329b4c4d33b114f8c781ebb2e306ff9dc6969d106ece2567e312b2dd15", - "sha256:a95adcecd8c5b6aafedbf0094217f9251589a5a350b3db54aa55b6cabc26a7ff" + "sha256:184f854fc716754ff07cd9f601923d1ce30a6826617e7c2b252abebe76746b6d", + "sha256:44145447d473c37ff2776667b5e1018a00c0a493c16a0a489399521b3786a8be" ], - "version": "==1.4.0.20210816" + "version": "==1.4.0.20210819" }, "portend": { "hashes": [ @@ -804,7 +849,7 @@ "sha256:65540c21bfe14405a3a77e4c085ecfce88724743a4ead47c66b84defcf82c32e", "sha256:9ce5fa65b8992dfa373bddc5b6e0864ead8f291c94fbfec05fbd5c836162e67b" ], - "markers": "sys_platform == 'win32'", + "markers": "python_version < '3.8' and sys_platform == 'win32'", "version": "==2.1" }, "pysmb": { @@ -815,24 +860,9 @@ "version": "==1.2.5" }, "pyspnego": { - "hashes": [ - "sha256:0356bccedc033b7266d89503eca50717f81fc9d3b98cb1dd5227bb7c1a9275ae", - "sha256:0940e0bdec72c6266ef9604db929ddda86f1dafe2c804ac3d6e30161a53e414d", - "sha256:44469f7cf2a9435d7115c557db4df6bd6a74ce0056511b88b672b58ff2d477f7", - "sha256:507809d2e1fc8733a4f0801ee59d01db646b41d3ab8b90a6f3a16a17eef3fc37", - "sha256:5701dd50597c0a11b4bd1d3921fd1c32ba3b7ec15c3e273c486870efe673dd52", - "sha256:5be3fa80bc81a11b9254e3800aa350db06b2eb1b9d830f7770a1baadae415185", - "sha256:777c9524e91298b2ec3d728dbb85e44d047ddd857db6c2658d977401fedfcc9c", - "sha256:83d52b9e8b55243fa3711d89e77d94935a60b8638e8659b572dee898d359bbe6", - "sha256:c05aa1efcb9b0cf3c6341c48a6b349c3b669b0d7d99ab65a789c0c1071701136", - "sha256:cc57132ebe7b6b5d14e940bf4069a1206ad0fe23f51281dee4e7979b34a369d3", - "sha256:d3e7d55447cc353765cef6d77b3c57fd02f77ddc83a4fb3b4b696df92f908ae1", - "sha256:e021472424fcb477d9a211437f6a14c2d9cb59e20eeee9ae7992bd7deee50064", - "sha256:ed4fece1a834cc29377f43f4ff459ae7eb7c7d937cfd3e4b46676fe9984c8c74", - "sha256:f90a41f7d31e049f3a2e566f02ce06d86f13bbd2e3796b3af3bdb2be75c6e836" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==0.1.6" + "editable": true, + "git": "https://github.com/jborean93/pyspnego", + "ref": "3f748f210e4fb6b186b0036e1a0bf38762d64c37" }, "python-dateutil": { "hashes": [ @@ -961,11 +991,11 @@ }, "tqdm": { "hashes": [ - "sha256:80aead664e6c1672c4ae20dc50e1cdc5e20eeff9b14aa23ecd426375b28be588", - "sha256:a4d6d112e507ef98513ac119ead1159d286deab17dffedd96921412c2d236ff5" + "sha256:8dd278a422499cd6b727e6ae4061c40b48fce8b76d1ccbf5d34fca9b7f925b0c", + "sha256:d359de7217506c9851b7869f3708d8ee53ed70a1b8edbba4dbcb47442592920d" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==4.62.2" + "version": "==4.62.3" }, "typing-extensions": { "hashes": [ diff --git a/monkey/infection_monkey/exploit/powershell.py b/monkey/infection_monkey/exploit/powershell.py index 7b4aaec66..f2883bb63 100644 --- a/monkey/infection_monkey/exploit/powershell.py +++ b/monkey/infection_monkey/exploit/powershell.py @@ -47,7 +47,7 @@ class PowerShellExploiter(HostExploiter): def _exploit_host(self): try: - is_https = self._is_client_using_https() + use_ssl = self._is_client_using_https() except PowerShellRemotingDisabledError as e: logging.info(e) return False @@ -59,7 +59,7 @@ class PowerShellExploiter(HostExploiter): self._config.exploit_ntlm_hash_list, is_windows_os(), ) - auth_options = get_auth_options(credentials, is_https) + auth_options = [get_auth_options(creds, use_ssl) for creds in credentials] self._client = self._authenticate_via_brute_force(credentials, auth_options) if not self._client: diff --git a/monkey/infection_monkey/exploit/powershell_utils/auth_options.py b/monkey/infection_monkey/exploit/powershell_utils/auth_options.py index ad770de3c..1f53c1df5 100644 --- a/monkey/infection_monkey/exploit/powershell_utils/auth_options.py +++ b/monkey/infection_monkey/exploit/powershell_utils/auth_options.py @@ -1,10 +1,10 @@ from dataclasses import dataclass -from typing import List -from infection_monkey.exploit.powershell_utils.credentials import Credentials +from infection_monkey.exploit.powershell_utils.credentials import Credentials, SecretType AUTH_BASIC = "basic" AUTH_NEGOTIATE = "negotiate" +AUTH_NTLM = "ntlm" ENCRYPTION_AUTO = "auto" ENCRYPTION_NEVER = "never" @@ -16,15 +16,28 @@ class AuthOptions: ssl: bool -def get_auth_options(credentials: List[Credentials], use_ssl: bool) -> List[AuthOptions]: - auth_options = [] +def get_auth_options(credentials: Credentials, use_ssl: bool) -> AuthOptions: + ssl = _get_ssl(credentials, use_ssl) + auth_type = _get_auth_type(credentials) + encryption = _get_encryption(credentials) - for creds in credentials: - # Passwordless login only works with SSL false, AUTH_BASIC and ENCRYPTION_NEVER - ssl = False if creds.secret == "" else use_ssl - auth_type = AUTH_BASIC if creds.secret == "" else AUTH_NEGOTIATE - encryption = ENCRYPTION_NEVER if creds.secret == "" else ENCRYPTION_AUTO + return AuthOptions(auth_type, encryption, ssl) - auth_options.append(AuthOptions(auth_type, encryption, ssl)) - return auth_options +def _get_ssl(credentials: Credentials, use_ssl): + # Passwordless login only works with SSL false, AUTH_BASIC and ENCRYPTION_NEVER + return False if credentials.secret == "" else use_ssl + + +def _get_auth_type(credentials: Credentials): + if credentials.secret == "": + return AUTH_BASIC + + if credentials.secret_type in {SecretType.LM_HASH, SecretType.NT_HASH}: + return AUTH_NTLM + + return AUTH_NEGOTIATE + + +def _get_encryption(credentials: Credentials): + return ENCRYPTION_NEVER if credentials.secret == "" else ENCRYPTION_AUTO diff --git a/monkey/tests/unit_tests/infection_monkey/exploit/powershell_utils/test_auth_options.py b/monkey/tests/unit_tests/infection_monkey/exploit/powershell_utils/test_auth_options.py index d19fffbd0..ce5449051 100644 --- a/monkey/tests/unit_tests/infection_monkey/exploit/powershell_utils/test_auth_options.py +++ b/monkey/tests/unit_tests/infection_monkey/exploit/powershell_utils/test_auth_options.py @@ -2,86 +2,99 @@ from infection_monkey.exploit.powershell_utils.auth_options import ( AUTH_BASIC, AUTH_NEGOTIATE, + AUTH_NTLM, ENCRYPTION_AUTO, ENCRYPTION_NEVER, get_auth_options, ) from infection_monkey.exploit.powershell_utils.credentials import Credentials, SecretType -CREDENTIALS = [ - Credentials("user1", "password1", SecretType.PASSWORD), - Credentials("user2", "", SecretType.PASSWORD), - Credentials("user3", None, SecretType.CACHED), -] +CREDENTIALS_WITH_PASSWORD = Credentials("user1", "password1", SecretType.PASSWORD) +CREDENTIALS_EMPTY_PASSWORD = Credentials("user2", "", SecretType.PASSWORD) +CREDENTIALS_NONE_PASSWORD = Credentials("user3", None, SecretType.CACHED) +CREDENTIALS_LM_HASH = Credentials("user4", "LM_HASH:NONE", SecretType.LM_HASH) +CREDENTIALS_NT_HASH = Credentials("user5", "NONE:NT_HASH", SecretType.NT_HASH) def test_get_auth_options__ssl_true_with_password(): - auth_options = get_auth_options(CREDENTIALS, use_ssl=True) + auth_options = get_auth_options(CREDENTIALS_WITH_PASSWORD, use_ssl=True) - assert auth_options[0].ssl + assert auth_options.ssl def test_get_auth_options__ssl_true_empty_password(): - auth_options = get_auth_options(CREDENTIALS, use_ssl=True) + auth_options = get_auth_options(CREDENTIALS_EMPTY_PASSWORD, use_ssl=True) - assert not auth_options[1].ssl + assert not auth_options.ssl def test_get_auth_options__ssl_true_none_password(): - auth_options = get_auth_options(CREDENTIALS, use_ssl=True) + auth_options = get_auth_options(CREDENTIALS_NONE_PASSWORD, use_ssl=True) - assert auth_options[2].ssl + assert auth_options.ssl def test_get_auth_options__ssl_false_with_password(): - auth_options = get_auth_options(CREDENTIALS, use_ssl=False) + auth_options = get_auth_options(CREDENTIALS_WITH_PASSWORD, use_ssl=False) - assert not auth_options[0].ssl + assert not auth_options.ssl def test_get_auth_options__ssl_false_empty_password(): - auth_options = get_auth_options(CREDENTIALS, use_ssl=False) + auth_options = get_auth_options(CREDENTIALS_EMPTY_PASSWORD, use_ssl=False) - assert not auth_options[1].ssl + assert not auth_options.ssl def test_get_auth_options__ssl_false_none_password(): - auth_options = get_auth_options(CREDENTIALS, use_ssl=False) + auth_options = get_auth_options(CREDENTIALS_NONE_PASSWORD, use_ssl=False) - assert not auth_options[2].ssl + assert not auth_options.ssl def test_get_auth_options__auth_type_with_password(): - auth_options = get_auth_options(CREDENTIALS, use_ssl=False) + auth_options = get_auth_options(CREDENTIALS_WITH_PASSWORD, use_ssl=False) - assert auth_options[0].auth_type == AUTH_NEGOTIATE + assert auth_options.auth_type == AUTH_NEGOTIATE def test_get_auth_options__auth_type_empty_password(): - auth_options = get_auth_options(CREDENTIALS, use_ssl=False) + auth_options = get_auth_options(CREDENTIALS_EMPTY_PASSWORD, use_ssl=False) - assert auth_options[1].auth_type == AUTH_BASIC + assert auth_options.auth_type == AUTH_BASIC def test_get_auth_options__auth_type_none_password(): - auth_options = get_auth_options(CREDENTIALS, use_ssl=False) + auth_options = get_auth_options(CREDENTIALS_NONE_PASSWORD, use_ssl=False) - assert auth_options[2].auth_type == AUTH_NEGOTIATE + assert auth_options.auth_type == AUTH_NEGOTIATE + + +def test_get_auth_options__auth_type_with_LM_hash(): + auth_options = get_auth_options(CREDENTIALS_LM_HASH, use_ssl=False) + + assert auth_options.auth_type == AUTH_NTLM + + +def test_get_auth_options__auth_type_with_NT_hash(): + auth_options = get_auth_options(CREDENTIALS_NT_HASH, use_ssl=False) + + assert auth_options.auth_type == AUTH_NTLM def test_get_auth_options__encryption_with_password(): - auth_options = get_auth_options(CREDENTIALS, use_ssl=False) + auth_options = get_auth_options(CREDENTIALS_WITH_PASSWORD, use_ssl=False) - assert auth_options[0].encryption == ENCRYPTION_AUTO + assert auth_options.encryption == ENCRYPTION_AUTO def test_get_auth_options__encryption_empty_password(): - auth_options = get_auth_options(CREDENTIALS, use_ssl=False) + auth_options = get_auth_options(CREDENTIALS_EMPTY_PASSWORD, use_ssl=False) - assert auth_options[1].encryption == ENCRYPTION_NEVER + assert auth_options.encryption == ENCRYPTION_NEVER def test_get_auth_options__encryption_none_password(): - auth_options = get_auth_options(CREDENTIALS, use_ssl=False) + auth_options = get_auth_options(CREDENTIALS_NONE_PASSWORD, use_ssl=False) - assert auth_options[2].encryption == ENCRYPTION_AUTO + assert auth_options.encryption == ENCRYPTION_AUTO