Google Forms (WordPress plugin) SSRF vulnerability

Overview

Google Forms is a WordPress plugin that can be used to embed forms from Google Docs. It has 20,000+ active install as of January 2018. There was a vulnerability that allowed unauthenticated users to proxy HTTP requests through the WordPress server using this plugin.

Details

In order to display forms from Google Docs, the plugin has to retrieve them via a HTTP request. When a Google form is viewed on WordPress, the POST variable “wpgform-action” may contain a base64 encoded double-quoted URL of the form on google.com.

There was a security check to ensure the URL belongs to google.com but it wasn’t adequate:

//  As a safety precaution make sure the action provided resolves to Google (docs.google.com drive.google.com).
if (!preg_match( '/^(http|https):\\/\\/(docs|drive)\.google\.com/i' ,$action))
	// ....

URLs such as “https://docs.google.com.evildomain.com/form.html” or “https://docs.google.com@localhost:8000/” would pass this check. An attacker could use this bug to perform HTTP requests to arbitrary hosts and ports from the vulnerable server. The request is a POST request and parameters supplied by the attacker are relayed.

The plugin does some processing with the response which restricts the exploit scenarios a bit. Anything up to the first <div> element is removed. The response shown to the attacker will be empty if the response doesn’t contain a div element.

On the other hand, connection errors are displayed so the attacker could use this bug for port scanning e.g. internal networks.

Another way to exploit the bug is a POST-based XSS attack. The attacker could create an automatically submitting HTML form with a “wpgform-action” parameter pointing to their own HTML document containing malicious JavaScript.

The plugin sanitizes the response HTML before displaying it. However after this sanitization there is another processing step which allows injecting JavaScript. Example:

<div>
<form action="aaa onmouseover=alert(/xss/) class=dropdown-backdrop x"></form>
</div>

The action="aaa part would be removed. The class attribute would then become “active” to enlarge the form and the onmouseover handler would get executed when the mouse is moved.

The exploits require a valid WordPress nonce (CSRF token) but the attacker can get a nonce by simply viewing the form page HTML source. The nonce check however probably mitigates the XSS scenario against logged-in users but not against unauthenticated users.

Proof of Concept

1. Get a nonce (CSRF token). The URL must point to a valid Google Forms page on the WordPress site.

$ curl -s 'https://server/wpgforms/123/' | grep wpgform_nonce

<input type="hidden" id="wpgform_nonce" name="wpgform_nonce" value="952798a7c8" />

2. Base64 encode a double-quoted target URL.

echo '"https://drive.google.com@klikki.fi/"' | base64

Imh0dHBzOi8vZHJpdmUuZ29vZ2xlLmNvbUBrbGlra2kuZmkvIgo=

3. Execute the SSRF:

$ curl -s 'https://server/wpgforms/22818/' --data 'wpgform_nonce=952798a7c8&wpgform-action=Imh0dHBzOi8vZHJpdmUuZ29vZ2xlLmNvbUBrbGlra2kuZmkvIgo='
...
    <h4 class="modal-title">Klikki Oy | Contact us</h4>
...

Vendor response

The bug was reported to the author on October 13, 2017 and fixed in January 2018 (version 0.92).

Bug bounty

There was also a bug bounty. A company using the plugin on their main website was offering bounties up to $10,000 for critical vulnerabilities, mentioning SSRF as an example. In this case the bug was assessed “low” impact and the bounty was $750.

Credits

The vulnerability was found by Jouko Pynnönen of Klikki Oy, Finland.